Fix debian bug#543530
[gnupg.git] / common / estream.c
blobc26df63237d8f4a6457d968ff56f84fef310113c
1 /* estream.c - Extended Stream I/O Library
2 * Copyright (C) 2004, 2005, 2006, 2007, 2009 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 /* Locking. */
96 #ifdef HAVE_PTH
98 typedef pth_mutex_t estream_mutex_t;
99 # define ESTREAM_MUTEX_INITIALIZER PTH_MUTEX_INIT
100 # define ESTREAM_MUTEX_LOCK(mutex) \
101 pth_mutex_acquire (&(mutex), 0, NULL)
102 # define ESTREAM_MUTEX_UNLOCK(mutex) \
103 pth_mutex_release (&(mutex))
104 # define ESTREAM_MUTEX_TRYLOCK(mutex) \
105 ((pth_mutex_acquire (&(mutex), 1, NULL) == TRUE) ? 0 : -1)
106 # define ESTREAM_MUTEX_INITIALIZE(mutex) \
107 pth_mutex_init (&(mutex))
108 #else
110 typedef void *estream_mutex_t;
112 static inline void
113 dummy_mutex_call_void (estream_mutex_t mutex)
115 (void)mutex;
118 static inline int
119 dummy_mutex_call_int (estream_mutex_t mutex)
121 (void)mutex;
122 return 0;
125 # define ESTREAM_MUTEX_INITIALIZER NULL
126 # define ESTREAM_MUTEX_LOCK(mutex) dummy_mutex_call_void ((mutex))
127 # define ESTREAM_MUTEX_UNLOCK(mutex) dummy_mutex_call_void ((mutex))
128 # define ESTREAM_MUTEX_TRYLOCK(mutex) dummy_mutex_call_int ((mutex))
129 # define ESTREAM_MUTEX_INITIALIZE(mutex) dummy_mutex_call_void ((mutex))
130 #endif
132 /* Primitive system I/O. */
134 #ifdef HAVE_PTH
135 # define ESTREAM_SYS_READ es_pth_read
136 # define ESTREAM_SYS_WRITE es_pth_write
137 #else
138 # define ESTREAM_SYS_READ read
139 # define ESTREAM_SYS_WRITE write
140 #endif
142 /* Misc definitions. */
144 #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR)
146 /* An internal stream object. */
148 struct estream_internal
150 unsigned char buffer[BUFFER_BLOCK_SIZE];
151 unsigned char unread_buffer[BUFFER_UNREAD_SIZE];
152 estream_mutex_t lock; /* Lock. */
153 void *cookie; /* Cookie. */
154 void *opaque; /* Opaque data. */
155 unsigned int modeflags; /* Flags for the backend. */
156 off_t offset;
157 es_cookie_read_function_t func_read;
158 es_cookie_write_function_t func_write;
159 es_cookie_seek_function_t func_seek;
160 es_cookie_close_function_t func_close;
161 int strategy;
162 int fd;
163 struct
165 unsigned int err: 1;
166 unsigned int eof: 1;
167 } indicators;
168 unsigned int deallocate_buffer: 1;
169 unsigned int print_err: 1; /* Error in print_fun_writer. */
170 int print_errno; /* Errno from print_fun_writer. */
171 size_t print_ntotal; /* Bytes written from in print_fun_writer. */
172 FILE *print_fp; /* Stdio stream used by print_fun_writer. */
176 typedef struct estream_internal *estream_internal_t;
178 #define ESTREAM_LOCK(stream) ESTREAM_MUTEX_LOCK (stream->intern->lock)
179 #define ESTREAM_UNLOCK(stream) ESTREAM_MUTEX_UNLOCK (stream->intern->lock)
180 #define ESTREAM_TRYLOCK(stream) ESTREAM_MUTEX_TRYLOCK (stream->intern->lock)
182 /* Stream list. */
184 typedef struct estream_list *estream_list_t;
186 struct estream_list
188 estream_t car;
189 estream_list_t cdr;
190 estream_list_t *prev_cdr;
193 static estream_list_t estream_list;
194 static estream_mutex_t estream_list_lock;
196 #define ESTREAM_LIST_LOCK ESTREAM_MUTEX_LOCK (estream_list_lock)
197 #define ESTREAM_LIST_UNLOCK ESTREAM_MUTEX_UNLOCK (estream_list_lock)
199 #ifndef EOPNOTSUPP
200 # define EOPNOTSUPP ENOSYS
201 #endif
206 /* Macros. */
208 /* Calculate array dimension. */
209 #ifndef DIM
210 #define DIM(array) (sizeof (array) / sizeof (*array))
211 #endif
213 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
216 /* Evaluate EXPRESSION, setting VARIABLE to the return code, if
217 VARIABLE is zero. */
218 #define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
219 do \
221 tmp_variable = expression; \
222 if ((! variable) && tmp_variable) \
223 variable = tmp_variable; \
225 while (0)
228 /* Malloc wrappers to overcome problems on some older OSes. */
229 static void *
230 mem_alloc (size_t n)
232 if (!n)
233 n++;
234 return malloc (n);
237 static void *
238 mem_realloc (void *p, size_t n)
240 if (!p)
241 return mem_alloc (n);
242 return realloc (p, n);
245 static void
246 mem_free (void *p)
248 if (p)
249 free (p);
255 * List manipulation.
258 /* Add STREAM to the list of registered stream objects. */
259 static int
260 es_list_add (estream_t stream)
262 estream_list_t list_obj;
263 int ret;
265 list_obj = mem_alloc (sizeof (*list_obj));
266 if (! list_obj)
267 ret = -1;
268 else
270 ESTREAM_LIST_LOCK;
271 list_obj->car = stream;
272 list_obj->cdr = estream_list;
273 list_obj->prev_cdr = &estream_list;
274 if (estream_list)
275 estream_list->prev_cdr = &list_obj->cdr;
276 estream_list = list_obj;
277 ESTREAM_LIST_UNLOCK;
278 ret = 0;
281 return ret;
284 /* Remove STREAM from the list of registered stream objects. */
285 static void
286 es_list_remove (estream_t stream)
288 estream_list_t list_obj;
290 ESTREAM_LIST_LOCK;
291 for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
292 if (list_obj->car == stream)
294 *list_obj->prev_cdr = list_obj->cdr;
295 if (list_obj->cdr)
296 list_obj->cdr->prev_cdr = list_obj->prev_cdr;
297 mem_free (list_obj);
298 break;
300 ESTREAM_LIST_UNLOCK;
303 /* Type of an stream-iterator-function. */
304 typedef int (*estream_iterator_t) (estream_t stream);
306 /* Iterate over list of registered streams, calling ITERATOR for each
307 of them. */
308 static int
309 es_list_iterate (estream_iterator_t iterator)
311 estream_list_t list_obj;
312 int ret = 0;
314 ESTREAM_LIST_LOCK;
315 for (list_obj = estream_list; list_obj; list_obj = list_obj->cdr)
316 ret |= (*iterator) (list_obj->car);
317 ESTREAM_LIST_UNLOCK;
319 return ret;
325 * I/O Helper
327 * Unfortunately our Pth emulation for Windows expects system handles
328 * for pth_read and pth_write. We use a simple approach to fix this:
329 * If the function returns an error we fall back to a vanilla read or
330 * write, assuming that we do I/O on a plain file where the operation
331 * can't block.
333 #ifdef HAVE_PTH
334 static int
335 es_pth_read (int fd, void *buffer, size_t size)
337 # ifdef HAVE_W32_SYSTEM
338 int rc = pth_read (fd, buffer, size);
339 if (rc == -1 && errno == EINVAL)
340 rc = read (fd, buffer, size);
341 return rc;
342 # else /*!HAVE_W32_SYSTEM*/
343 return pth_read (fd, buffer, size);
344 # endif /* !HAVE_W32_SYSTEM*/
347 static int
348 es_pth_write (int fd, const void *buffer, size_t size)
350 # ifdef HAVE_W32_SYSTEM
351 int rc = pth_write (fd, buffer, size);
352 if (rc == -1 && errno == EINVAL)
353 rc = write (fd, buffer, size);
354 return rc;
355 # else /*!HAVE_W32_SYSTEM*/
356 return pth_write (fd, buffer, size);
357 # endif /* !HAVE_W32_SYSTEM*/
359 #endif /*HAVE_PTH*/
364 * Initialization.
367 static int
368 es_init_do (void)
370 #ifdef HAVE_PTH
371 static int initialized;
373 if (!initialized)
375 if (!pth_init () && errno != EPERM )
376 return -1;
377 if (pth_mutex_init (&estream_list_lock))
378 initialized = 1;
380 #endif
381 return 0;
387 * I/O methods.
390 /* Implementation of Memory I/O. */
392 /* Cookie for memory objects. */
393 typedef struct estream_cookie_mem
395 unsigned int modeflags; /* Open flags. */
396 unsigned char *memory; /* Allocated data buffer. */
397 size_t memory_size; /* Allocated size of MEMORY. */
398 size_t memory_limit; /* Caller supplied maximum allowed
399 allocation size or 0 for no limit. */
400 size_t offset; /* Current offset in MEMORY. */
401 size_t data_len; /* Used length of data in MEMORY. */
402 size_t block_size; /* Block size. */
403 struct {
404 unsigned int grow: 1; /* MEMORY is allowed to grow. */
405 } flags;
406 func_realloc_t func_realloc;
407 func_free_t func_free;
408 } *estream_cookie_mem_t;
411 /* Create function for memory objects. DATA is either NULL or a user
412 supplied buffer with the initial conetnt of the memory buffer. If
413 DATA is NULL, DATA_N and DATA_LEN need to be 0 as well. If DATA is
414 not NULL, DATA_N gives the allocated size of DATA and DATA_LEN the
415 used length in DATA. */
416 static int
417 es_func_mem_create (void *ES__RESTRICT *ES__RESTRICT cookie,
418 unsigned char *ES__RESTRICT data, size_t data_n,
419 size_t data_len,
420 size_t block_size, unsigned int grow,
421 func_realloc_t func_realloc, func_free_t func_free,
422 unsigned int modeflags,
423 size_t memory_limit)
425 estream_cookie_mem_t mem_cookie;
426 int err;
428 if (!data && (data_n || data_len))
430 errno = EINVAL;
431 return -1;
434 mem_cookie = mem_alloc (sizeof (*mem_cookie));
435 if (!mem_cookie)
436 err = -1;
437 else
439 mem_cookie->modeflags = modeflags;
440 mem_cookie->memory = data;
441 mem_cookie->memory_size = data_n;
442 mem_cookie->memory_limit = memory_limit;
443 mem_cookie->offset = 0;
444 mem_cookie->data_len = data_len;
445 mem_cookie->block_size = block_size;
446 mem_cookie->flags.grow = !!grow;
447 mem_cookie->func_realloc = func_realloc ? func_realloc : mem_realloc;
448 mem_cookie->func_free = func_free ? func_free : mem_free;
449 *cookie = mem_cookie;
450 err = 0;
453 return err;
457 /* Read function for memory objects. */
458 static ssize_t
459 es_func_mem_read (void *cookie, void *buffer, size_t size)
461 estream_cookie_mem_t mem_cookie = cookie;
462 ssize_t ret;
464 if (size > mem_cookie->data_len - mem_cookie->offset)
465 size = mem_cookie->data_len - mem_cookie->offset;
467 if (size)
469 memcpy (buffer, mem_cookie->memory + mem_cookie->offset, size);
470 mem_cookie->offset += size;
473 ret = size;
474 return ret;
478 /* Write function for memory objects. */
479 static ssize_t
480 es_func_mem_write (void *cookie, const void *buffer, size_t size)
482 estream_cookie_mem_t mem_cookie = cookie;
483 ssize_t ret;
484 size_t nleft;
486 if (!size)
487 return 0; /* A flush is a NOP for memory objects. */
489 if (mem_cookie->modeflags & O_APPEND)
491 /* Append to data. */
492 mem_cookie->offset = mem_cookie->data_len;
495 assert (mem_cookie->memory_size >= mem_cookie->offset);
496 nleft = mem_cookie->memory_size - mem_cookie->offset;
498 /* If we are not allowed to grow limit the size to the left space. */
499 if (!mem_cookie->flags.grow && size > nleft)
500 size = nleft;
502 /* Enlarge the memory buffer if needed. */
503 if (size > nleft)
505 unsigned char *newbuf;
506 size_t newsize;
508 if (!mem_cookie->memory_size)
509 newsize = size; /* Not yet allocated. */
510 else
511 newsize = mem_cookie->memory_size + (nleft - size);
512 if (newsize < mem_cookie->offset)
514 errno = EINVAL;
515 return -1;
518 /* Round up to the next block length. BLOCK_SIZE should always
519 be set; we check anyway. */
520 if (mem_cookie->block_size)
522 newsize += mem_cookie->block_size - 1;
523 if (newsize < mem_cookie->offset)
525 errno = EINVAL;
526 return -1;
528 newsize /= mem_cookie->block_size;
529 newsize *= mem_cookie->block_size;
532 /* Check for a total limit. */
533 if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
535 errno = ENOSPC;
536 return -1;
539 newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
540 if (!newbuf)
541 return -1;
543 mem_cookie->memory = newbuf;
544 mem_cookie->memory_size = newsize;
546 assert (mem_cookie->memory_size >= mem_cookie->offset);
547 nleft = mem_cookie->memory_size - mem_cookie->offset;
549 assert (size <= nleft);
552 memcpy (mem_cookie->memory + mem_cookie->offset, buffer, size);
553 if (mem_cookie->offset + size > mem_cookie->data_len)
554 mem_cookie->data_len = mem_cookie->offset + size;
555 mem_cookie->offset += size;
557 ret = size;
558 return ret;
562 /* Seek function for memory objects. */
563 static int
564 es_func_mem_seek (void *cookie, off_t *offset, int whence)
566 estream_cookie_mem_t mem_cookie = cookie;
567 off_t pos_new;
569 switch (whence)
571 case SEEK_SET:
572 pos_new = *offset;
573 break;
575 case SEEK_CUR:
576 pos_new = mem_cookie->offset += *offset;
577 break;
579 case SEEK_END:
580 pos_new = mem_cookie->data_len += *offset;
581 break;
583 default:
584 errno = EINVAL;
585 return -1;
588 if (pos_new > mem_cookie->memory_size)
590 size_t newsize;
591 void *newbuf;
593 if (!mem_cookie->flags.grow)
595 errno = ENOSPC;
596 return -1;
599 newsize = pos_new + mem_cookie->block_size - 1;
600 if (newsize < pos_new)
602 errno = EINVAL;
603 return -1;
605 newsize /= mem_cookie->block_size;
606 newsize *= mem_cookie->block_size;
608 if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit)
610 errno = ENOSPC;
611 return -1;
614 newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize);
615 if (!newbuf)
616 return -1;
618 mem_cookie->memory = newbuf;
619 mem_cookie->memory_size = newsize;
622 if (pos_new > mem_cookie->data_len)
624 /* Fill spare space with zeroes. */
625 memset (mem_cookie->memory + mem_cookie->data_len,
626 0, pos_new - mem_cookie->data_len);
627 mem_cookie->data_len = pos_new;
630 mem_cookie->offset = pos_new;
631 *offset = pos_new;
633 return 0;
637 /* Destroy function for memory objects. */
638 static int
639 es_func_mem_destroy (void *cookie)
641 estream_cookie_mem_t mem_cookie = cookie;
643 if (cookie)
645 mem_cookie->func_free (mem_cookie->memory);
646 mem_free (mem_cookie);
648 return 0;
652 static es_cookie_io_functions_t estream_functions_mem =
654 es_func_mem_read,
655 es_func_mem_write,
656 es_func_mem_seek,
657 es_func_mem_destroy
662 /* Implementation of fd I/O. */
664 /* Cookie for fd objects. */
665 typedef struct estream_cookie_fd
667 int fd; /* The file descriptor we are using for actual output. */
668 int no_close; /* If set we won't close the file descriptor. */
669 } *estream_cookie_fd_t;
671 /* Create function for fd objects. */
672 static int
673 es_func_fd_create (void **cookie, int fd, unsigned int modeflags, int no_close)
675 estream_cookie_fd_t fd_cookie;
676 int err;
678 fd_cookie = mem_alloc (sizeof (*fd_cookie));
679 if (! fd_cookie)
680 err = -1;
681 else
683 #ifdef HAVE_DOSISH_SYSTEM
684 /* Make sure it is in binary mode if requested. */
685 if ( (modeflags & O_BINARY) )
686 setmode (fd, O_BINARY);
687 #else
688 (void)modeflags;
689 #endif
690 fd_cookie->fd = fd;
691 fd_cookie->no_close = no_close;
692 *cookie = fd_cookie;
693 err = 0;
696 return err;
699 /* Read function for fd objects. */
700 static ssize_t
701 es_func_fd_read (void *cookie, void *buffer, size_t size)
704 estream_cookie_fd_t file_cookie = cookie;
705 ssize_t bytes_read;
708 bytes_read = ESTREAM_SYS_READ (file_cookie->fd, buffer, size);
709 while (bytes_read == -1 && errno == EINTR);
711 return bytes_read;
714 /* Write function for fd objects. */
715 static ssize_t
716 es_func_fd_write (void *cookie, const void *buffer, size_t size)
719 estream_cookie_fd_t file_cookie = cookie;
720 ssize_t bytes_written;
723 bytes_written = ESTREAM_SYS_WRITE (file_cookie->fd, buffer, size);
724 while (bytes_written == -1 && errno == EINTR);
726 return bytes_written;
729 /* Seek function for fd objects. */
730 static int
731 es_func_fd_seek (void *cookie, off_t *offset, int whence)
733 estream_cookie_fd_t file_cookie = cookie;
734 off_t offset_new;
735 int err;
737 offset_new = lseek (file_cookie->fd, *offset, whence);
738 if (offset_new == -1)
739 err = -1;
740 else
742 *offset = offset_new;
743 err = 0;
746 return err;
749 /* Destroy function for fd objects. */
750 static int
751 es_func_fd_destroy (void *cookie)
753 estream_cookie_fd_t fd_cookie = cookie;
754 int err;
756 if (fd_cookie)
758 err = fd_cookie->no_close? 0 : close (fd_cookie->fd);
759 mem_free (fd_cookie);
761 else
762 err = 0;
764 return err;
768 static es_cookie_io_functions_t estream_functions_fd =
770 es_func_fd_read,
771 es_func_fd_write,
772 es_func_fd_seek,
773 es_func_fd_destroy
779 /* Implementation of FILE* I/O. */
781 /* Cookie for fp objects. */
782 typedef struct estream_cookie_fp
784 FILE *fp; /* The file pointer we are using for actual output. */
785 int no_close; /* If set we won't close the file pointer. */
786 } *estream_cookie_fp_t;
788 /* Create function for fd objects. */
789 static int
790 es_func_fp_create (void **cookie, FILE *fp,
791 unsigned int modeflags, int no_close)
793 estream_cookie_fp_t fp_cookie;
794 int err;
796 fp_cookie = mem_alloc (sizeof *fp_cookie);
797 if (!fp_cookie)
798 err = -1;
799 else
801 #ifdef HAVE_DOSISH_SYSTEM
802 /* Make sure it is in binary mode if requested. */
803 if ( (modeflags & O_BINARY) )
804 setmode (fileno (fp), O_BINARY);
805 #else
806 (void)modeflags;
807 #endif
808 fp_cookie->fp = fp;
809 fp_cookie->no_close = no_close;
810 *cookie = fp_cookie;
811 err = 0;
814 return err;
817 /* Read function for FILE* objects. */
818 static ssize_t
819 es_func_fp_read (void *cookie, void *buffer, size_t size)
822 estream_cookie_fp_t file_cookie = cookie;
823 ssize_t bytes_read;
825 bytes_read = fread (buffer, 1, size, file_cookie->fp);
826 if (!bytes_read && ferror (file_cookie->fp))
827 return -1;
828 return bytes_read;
831 /* Write function for FILE* objects. */
832 static ssize_t
833 es_func_fp_write (void *cookie, const void *buffer, size_t size)
836 estream_cookie_fp_t file_cookie = cookie;
837 size_t bytes_written;
839 bytes_written = fwrite (buffer, 1, size, file_cookie->fp);
840 if (bytes_written != size)
841 return -1;
842 return bytes_written;
845 /* Seek function for FILE* objects. */
846 static int
847 es_func_fp_seek (void *cookie, off_t *offset, int whence)
849 estream_cookie_fp_t file_cookie = cookie;
850 long int offset_new;
852 if ( fseek (file_cookie->fp, (long int)*offset, whence) )
854 fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", errno,strerror (errno));
855 return -1;
858 offset_new = ftell (file_cookie->fp);
859 if (offset_new == -1)
861 fprintf (stderr, "\nftell failed: errno=%d (%s)\n", errno,strerror (errno));
862 return -1;
864 *offset = offset_new;
865 return 0;
868 /* Destroy function for fd objects. */
869 static int
870 es_func_fp_destroy (void *cookie)
872 estream_cookie_fp_t fp_cookie = cookie;
873 int err;
875 if (fp_cookie)
877 fflush (fp_cookie->fp);
878 err = fp_cookie->no_close? 0 : fclose (fp_cookie->fp);
879 mem_free (fp_cookie);
881 else
882 err = 0;
884 return err;
888 static es_cookie_io_functions_t estream_functions_fp =
890 es_func_fp_read,
891 es_func_fp_write,
892 es_func_fp_seek,
893 es_func_fp_destroy
899 /* Implementation of file I/O. */
901 /* Create function for file objects. */
902 static int
903 es_func_file_create (void **cookie, int *filedes,
904 const char *path, unsigned int modeflags)
906 estream_cookie_fd_t file_cookie;
907 int err;
908 int fd;
910 err = 0;
911 fd = -1;
913 file_cookie = mem_alloc (sizeof (*file_cookie));
914 if (! file_cookie)
916 err = -1;
917 goto out;
920 fd = open (path, modeflags, ES_DEFAULT_OPEN_MODE);
921 if (fd == -1)
923 err = -1;
924 goto out;
926 #ifdef HAVE_DOSISH_SYSTEM
927 /* Make sure it is in binary mode if requested. */
928 if ( (modeflags & O_BINARY) )
929 setmode (fd, O_BINARY);
930 #endif
932 file_cookie->fd = fd;
933 file_cookie->no_close = 0;
934 *cookie = file_cookie;
935 *filedes = fd;
937 out:
939 if (err)
940 mem_free (file_cookie);
942 return err;
945 static es_cookie_io_functions_t estream_functions_file =
947 es_func_fd_read,
948 es_func_fd_write,
949 es_func_fd_seek,
950 es_func_fd_destroy
954 static int
955 es_convert_mode (const char *mode, unsigned int *modeflags)
957 unsigned int omode, oflags;
959 switch (*mode)
961 case 'r':
962 omode = O_RDONLY;
963 oflags = 0;
964 break;
965 case 'w':
966 omode = O_WRONLY;
967 oflags = O_TRUNC | O_CREAT;
968 break;
969 case 'a':
970 omode = O_WRONLY;
971 oflags = O_APPEND | O_CREAT;
972 break;
973 default:
974 errno = EINVAL;
975 return -1;
977 for (mode++; *mode; mode++)
979 switch (*mode)
981 case '+':
982 omode = O_RDWR;
983 break;
984 case 'b':
985 oflags |= O_BINARY;
986 break;
987 case 'x':
988 oflags |= O_EXCL;
989 break;
990 default: /* Ignore unknown flags. */
991 break;
995 *modeflags = (omode | oflags);
996 return 0;
1002 * Low level stream functionality.
1005 static int
1006 es_fill (estream_t stream)
1008 size_t bytes_read = 0;
1009 int err;
1011 if (!stream->intern->func_read)
1013 errno = EOPNOTSUPP;
1014 err = -1;
1016 else
1018 es_cookie_read_function_t func_read = stream->intern->func_read;
1019 ssize_t ret;
1021 ret = (*func_read) (stream->intern->cookie,
1022 stream->buffer, stream->buffer_size);
1023 if (ret == -1)
1025 bytes_read = 0;
1026 err = -1;
1028 else
1030 bytes_read = ret;
1031 err = 0;
1035 if (err)
1036 stream->intern->indicators.err = 1;
1037 else if (!bytes_read)
1038 stream->intern->indicators.eof = 1;
1040 stream->intern->offset += stream->data_len;
1041 stream->data_len = bytes_read;
1042 stream->data_offset = 0;
1044 return err;
1047 static int
1048 es_flush (estream_t stream)
1050 es_cookie_write_function_t func_write = stream->intern->func_write;
1051 int err;
1053 assert (stream->flags.writing);
1055 if (stream->data_offset)
1057 size_t bytes_written;
1058 size_t data_flushed;
1059 ssize_t ret;
1061 if (! func_write)
1063 err = EOPNOTSUPP;
1064 goto out;
1067 /* Note: to prevent an endless loop caused by user-provided
1068 write-functions that pretend to have written more bytes than
1069 they were asked to write, we have to check for
1070 "(stream->data_offset - data_flushed) > 0" instead of
1071 "stream->data_offset - data_flushed". */
1073 data_flushed = 0;
1074 err = 0;
1076 while ((((ssize_t) (stream->data_offset - data_flushed)) > 0) && (! err))
1078 ret = (*func_write) (stream->intern->cookie,
1079 stream->buffer + data_flushed,
1080 stream->data_offset - data_flushed);
1081 if (ret == -1)
1083 bytes_written = 0;
1084 err = -1;
1086 else
1087 bytes_written = ret;
1089 data_flushed += bytes_written;
1090 if (err)
1091 break;
1094 stream->data_flushed += data_flushed;
1095 if (stream->data_offset == data_flushed)
1097 stream->intern->offset += stream->data_offset;
1098 stream->data_offset = 0;
1099 stream->data_flushed = 0;
1101 /* Propagate flush event. */
1102 (*func_write) (stream->intern->cookie, NULL, 0);
1105 else
1106 err = 0;
1108 out:
1110 if (err)
1111 stream->intern->indicators.err = 1;
1113 return err;
1116 /* Discard buffered data for STREAM. */
1117 static void
1118 es_empty (estream_t stream)
1120 assert (!stream->flags.writing);
1121 stream->data_len = 0;
1122 stream->data_offset = 0;
1123 stream->unread_data_len = 0;
1126 /* Initialize STREAM. */
1127 static void
1128 es_initialize (estream_t stream,
1129 void *cookie, int fd, es_cookie_io_functions_t functions,
1130 unsigned int modeflags)
1132 stream->intern->cookie = cookie;
1133 stream->intern->opaque = NULL;
1134 stream->intern->offset = 0;
1135 stream->intern->func_read = functions.func_read;
1136 stream->intern->func_write = functions.func_write;
1137 stream->intern->func_seek = functions.func_seek;
1138 stream->intern->func_close = functions.func_close;
1139 stream->intern->strategy = _IOFBF;
1140 stream->intern->fd = fd;
1141 stream->intern->print_err = 0;
1142 stream->intern->print_errno = 0;
1143 stream->intern->print_ntotal = 0;
1144 stream->intern->print_fp = NULL;
1145 stream->intern->indicators.err = 0;
1146 stream->intern->indicators.eof = 0;
1147 stream->intern->deallocate_buffer = 0;
1149 stream->data_len = 0;
1150 stream->data_offset = 0;
1151 stream->data_flushed = 0;
1152 stream->unread_data_len = 0;
1153 /* Depending on the modeflags we set whether we start in writing or
1154 reading mode. This is required in case we are working on a
1155 wronly stream which is not seeekable (like stdout). Without this
1156 pre-initialization we would do a seek at the first write call and
1157 as this will fail no utput will be delivered. */
1158 if ((modeflags & O_WRONLY) || (modeflags & O_RDWR) )
1159 stream->flags.writing = 1;
1160 else
1161 stream->flags.writing = 0;
1164 /* Deinitialize STREAM. */
1165 static int
1166 es_deinitialize (estream_t stream)
1168 es_cookie_close_function_t func_close;
1169 int err, tmp_err;
1171 if (stream->intern->print_fp)
1173 int save_errno = errno;
1174 fclose (stream->intern->print_fp);
1175 stream->intern->print_fp = NULL;
1176 errno = save_errno;
1179 func_close = stream->intern->func_close;
1181 err = 0;
1182 if (stream->flags.writing)
1183 SET_UNLESS_NONZERO (err, tmp_err, es_flush (stream));
1184 if (func_close)
1185 SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie));
1188 return err;
1191 /* Create a new stream object, initialize it. */
1192 static int
1193 es_create (estream_t *stream, void *cookie, int fd,
1194 es_cookie_io_functions_t functions, unsigned int modeflags)
1196 estream_internal_t stream_internal_new;
1197 estream_t stream_new;
1198 int err;
1200 stream_new = NULL;
1201 stream_internal_new = NULL;
1203 stream_new = mem_alloc (sizeof (*stream_new));
1204 if (! stream_new)
1206 err = -1;
1207 goto out;
1210 stream_internal_new = mem_alloc (sizeof (*stream_internal_new));
1211 if (! stream_internal_new)
1213 err = -1;
1214 goto out;
1217 stream_new->buffer = stream_internal_new->buffer;
1218 stream_new->buffer_size = sizeof (stream_internal_new->buffer);
1219 stream_new->unread_buffer = stream_internal_new->unread_buffer;
1220 stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer);
1221 stream_new->intern = stream_internal_new;
1223 ESTREAM_MUTEX_INITIALIZE (stream_new->intern->lock);
1224 es_initialize (stream_new, cookie, fd, functions, modeflags);
1226 err = es_list_add (stream_new);
1227 if (err)
1228 goto out;
1230 *stream = stream_new;
1232 out:
1234 if (err)
1236 if (stream_new)
1238 es_deinitialize (stream_new);
1239 mem_free (stream_new);
1243 return err;
1246 /* Deinitialize a stream object and destroy it. */
1247 static int
1248 es_destroy (estream_t stream)
1250 int err = 0;
1252 if (stream)
1254 es_list_remove (stream);
1255 err = es_deinitialize (stream);
1256 mem_free (stream->intern);
1257 mem_free (stream);
1260 return err;
1263 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1264 unbuffered-mode, storing the amount of bytes read in
1265 *BYTES_READ. */
1266 static int
1267 es_read_nbf (estream_t ES__RESTRICT stream,
1268 unsigned char *ES__RESTRICT buffer,
1269 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1271 es_cookie_read_function_t func_read = stream->intern->func_read;
1272 size_t data_read;
1273 ssize_t ret;
1274 int err;
1276 data_read = 0;
1277 err = 0;
1279 while (bytes_to_read - data_read)
1281 ret = (*func_read) (stream->intern->cookie,
1282 buffer + data_read, bytes_to_read - data_read);
1283 if (ret == -1)
1285 err = -1;
1286 break;
1288 else if (ret)
1289 data_read += ret;
1290 else
1291 break;
1294 stream->intern->offset += data_read;
1295 *bytes_read = data_read;
1297 return err;
1300 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1301 fully-buffered-mode, storing the amount of bytes read in
1302 *BYTES_READ. */
1303 static int
1304 es_read_fbf (estream_t ES__RESTRICT stream,
1305 unsigned char *ES__RESTRICT buffer,
1306 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1308 size_t data_available;
1309 size_t data_to_read;
1310 size_t data_read;
1311 int err;
1313 data_read = 0;
1314 err = 0;
1316 while ((bytes_to_read - data_read) && (! err))
1318 if (stream->data_offset == stream->data_len)
1320 /* Nothing more to read in current container, try to
1321 fill container with new data. */
1322 err = es_fill (stream);
1323 if (! err)
1324 if (! stream->data_len)
1325 /* Filling did not result in any data read. */
1326 break;
1329 if (! err)
1331 /* Filling resulted in some new data. */
1333 data_to_read = bytes_to_read - data_read;
1334 data_available = stream->data_len - stream->data_offset;
1335 if (data_to_read > data_available)
1336 data_to_read = data_available;
1338 memcpy (buffer + data_read,
1339 stream->buffer + stream->data_offset, data_to_read);
1340 stream->data_offset += data_to_read;
1341 data_read += data_to_read;
1345 *bytes_read = data_read;
1347 return err;
1350 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER in
1351 line-buffered-mode, storing the amount of bytes read in
1352 *BYTES_READ. */
1353 static int
1354 es_read_lbf (estream_t ES__RESTRICT stream,
1355 unsigned char *ES__RESTRICT buffer,
1356 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1358 int err;
1360 err = es_read_fbf (stream, buffer, bytes_to_read, bytes_read);
1362 return err;
1365 /* Try to read BYTES_TO_READ bytes FROM STREAM into BUFFER, storing
1366 *the amount of bytes read in BYTES_READ. */
1367 static int
1368 es_readn (estream_t ES__RESTRICT stream,
1369 void *ES__RESTRICT buffer_arg,
1370 size_t bytes_to_read, size_t *ES__RESTRICT bytes_read)
1372 unsigned char *buffer = (unsigned char *)buffer_arg;
1373 size_t data_read_unread, data_read;
1374 int err;
1376 data_read_unread = 0;
1377 data_read = 0;
1378 err = 0;
1380 if (stream->flags.writing)
1382 /* Switching to reading mode -> flush output. */
1383 err = es_flush (stream);
1384 if (err)
1385 goto out;
1386 stream->flags.writing = 0;
1389 /* Read unread data first. */
1390 while ((bytes_to_read - data_read_unread) && stream->unread_data_len)
1392 buffer[data_read_unread]
1393 = stream->unread_buffer[stream->unread_data_len - 1];
1394 stream->unread_data_len--;
1395 data_read_unread++;
1398 switch (stream->intern->strategy)
1400 case _IONBF:
1401 err = es_read_nbf (stream,
1402 buffer + data_read_unread,
1403 bytes_to_read - data_read_unread, &data_read);
1404 break;
1405 case _IOLBF:
1406 err = es_read_lbf (stream,
1407 buffer + data_read_unread,
1408 bytes_to_read - data_read_unread, &data_read);
1409 break;
1410 case _IOFBF:
1411 err = es_read_fbf (stream,
1412 buffer + data_read_unread,
1413 bytes_to_read - data_read_unread, &data_read);
1414 break;
1417 out:
1419 if (bytes_read)
1420 *bytes_read = data_read_unread + data_read;
1422 return err;
1425 /* Try to unread DATA_N bytes from DATA into STREAM, storing the
1426 amount of bytes succesfully unread in *BYTES_UNREAD. */
1427 static void
1428 es_unreadn (estream_t ES__RESTRICT stream,
1429 const unsigned char *ES__RESTRICT data, size_t data_n,
1430 size_t *ES__RESTRICT bytes_unread)
1432 size_t space_left;
1434 space_left = stream->unread_buffer_size - stream->unread_data_len;
1436 if (data_n > space_left)
1437 data_n = space_left;
1439 if (! data_n)
1440 goto out;
1442 memcpy (stream->unread_buffer + stream->unread_data_len, data, data_n);
1443 stream->unread_data_len += data_n;
1444 stream->intern->indicators.eof = 0;
1446 out:
1448 if (bytes_unread)
1449 *bytes_unread = data_n;
1452 /* Seek in STREAM. */
1453 static int
1454 es_seek (estream_t ES__RESTRICT stream, off_t offset, int whence,
1455 off_t *ES__RESTRICT offset_new)
1457 es_cookie_seek_function_t func_seek = stream->intern->func_seek;
1458 int err, ret;
1459 off_t off;
1461 if (! func_seek)
1463 errno = EOPNOTSUPP;
1464 err = -1;
1465 goto out;
1468 if (stream->flags.writing)
1470 /* Flush data first in order to prevent flushing it to the wrong
1471 offset. */
1472 err = es_flush (stream);
1473 if (err)
1474 goto out;
1475 stream->flags.writing = 0;
1478 off = offset;
1479 if (whence == SEEK_CUR)
1481 off = off - stream->data_len + stream->data_offset;
1482 off -= stream->unread_data_len;
1485 ret = (*func_seek) (stream->intern->cookie, &off, whence);
1486 if (ret == -1)
1488 err = -1;
1489 goto out;
1492 err = 0;
1493 es_empty (stream);
1495 if (offset_new)
1496 *offset_new = off;
1498 stream->intern->indicators.eof = 0;
1499 stream->intern->offset = off;
1501 out:
1503 if (err)
1504 stream->intern->indicators.err = 1;
1506 return err;
1509 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1510 unbuffered-mode, storing the amount of bytes written in
1511 *BYTES_WRITTEN. */
1512 static int
1513 es_write_nbf (estream_t ES__RESTRICT stream,
1514 const unsigned char *ES__RESTRICT buffer,
1515 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1517 es_cookie_write_function_t func_write = stream->intern->func_write;
1518 size_t data_written;
1519 ssize_t ret;
1520 int err;
1522 if (bytes_to_write && (! func_write))
1524 err = EOPNOTSUPP;
1525 goto out;
1528 data_written = 0;
1529 err = 0;
1531 while (bytes_to_write - data_written)
1533 ret = (*func_write) (stream->intern->cookie,
1534 buffer + data_written,
1535 bytes_to_write - data_written);
1536 if (ret == -1)
1538 err = -1;
1539 break;
1541 else
1542 data_written += ret;
1545 stream->intern->offset += data_written;
1546 *bytes_written = data_written;
1548 out:
1550 return err;
1553 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1554 fully-buffered-mode, storing the amount of bytes written in
1555 *BYTES_WRITTEN. */
1556 static int
1557 es_write_fbf (estream_t ES__RESTRICT stream,
1558 const unsigned char *ES__RESTRICT buffer,
1559 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1561 size_t space_available;
1562 size_t data_to_write;
1563 size_t data_written;
1564 int err;
1566 data_written = 0;
1567 err = 0;
1569 while ((bytes_to_write - data_written) && (! err))
1571 if (stream->data_offset == stream->buffer_size)
1572 /* Container full, flush buffer. */
1573 err = es_flush (stream);
1575 if (! err)
1577 /* Flushing resulted in empty container. */
1579 data_to_write = bytes_to_write - data_written;
1580 space_available = stream->buffer_size - stream->data_offset;
1581 if (data_to_write > space_available)
1582 data_to_write = space_available;
1584 memcpy (stream->buffer + stream->data_offset,
1585 buffer + data_written, data_to_write);
1586 stream->data_offset += data_to_write;
1587 data_written += data_to_write;
1591 *bytes_written = data_written;
1593 return err;
1597 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in
1598 line-buffered-mode, storing the amount of bytes written in
1599 *BYTES_WRITTEN. */
1600 static int
1601 es_write_lbf (estream_t ES__RESTRICT stream,
1602 const unsigned char *ES__RESTRICT buffer,
1603 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1605 size_t data_flushed = 0;
1606 size_t data_buffered = 0;
1607 unsigned char *nlp;
1608 int err = 0;
1610 nlp = memrchr (buffer, '\n', bytes_to_write);
1611 if (nlp)
1613 /* Found a newline, directly write up to (including) this
1614 character. */
1615 err = es_flush (stream);
1616 if (!err)
1617 err = es_write_nbf (stream, buffer, nlp - buffer + 1, &data_flushed);
1620 if (!err)
1622 /* Write remaining data fully buffered. */
1623 err = es_write_fbf (stream, buffer + data_flushed,
1624 bytes_to_write - data_flushed, &data_buffered);
1627 *bytes_written = data_flushed + data_buffered;
1628 return err;
1632 /* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the
1633 amount of bytes written in BYTES_WRITTEN. */
1634 static int
1635 es_writen (estream_t ES__RESTRICT stream,
1636 const void *ES__RESTRICT buffer,
1637 size_t bytes_to_write, size_t *ES__RESTRICT bytes_written)
1639 size_t data_written;
1640 int err;
1642 data_written = 0;
1643 err = 0;
1645 if (!stream->flags.writing)
1647 /* Switching to writing mode -> discard input data and seek to
1648 position at which reading has stopped. We can do this only
1649 if a seek function has been registered. */
1650 if (stream->intern->func_seek)
1652 err = es_seek (stream, 0, SEEK_CUR, NULL);
1653 if (err)
1655 if (errno == ESPIPE)
1656 err = 0;
1657 else
1658 goto out;
1663 switch (stream->intern->strategy)
1665 case _IONBF:
1666 err = es_write_nbf (stream, buffer, bytes_to_write, &data_written);
1667 break;
1669 case _IOLBF:
1670 err = es_write_lbf (stream, buffer, bytes_to_write, &data_written);
1671 break;
1673 case _IOFBF:
1674 err = es_write_fbf (stream, buffer, bytes_to_write, &data_written);
1675 break;
1678 out:
1680 if (bytes_written)
1681 *bytes_written = data_written;
1682 if (data_written)
1683 if (!stream->flags.writing)
1684 stream->flags.writing = 1;
1686 return err;
1690 static int
1691 es_peek (estream_t ES__RESTRICT stream, unsigned char **ES__RESTRICT data,
1692 size_t *ES__RESTRICT data_len)
1694 int err;
1696 if (stream->flags.writing)
1698 /* Switching to reading mode -> flush output. */
1699 err = es_flush (stream);
1700 if (err)
1701 goto out;
1702 stream->flags.writing = 0;
1705 if (stream->data_offset == stream->data_len)
1707 /* Refill container. */
1708 err = es_fill (stream);
1709 if (err)
1710 goto out;
1713 if (data)
1714 *data = stream->buffer + stream->data_offset;
1715 if (data_len)
1716 *data_len = stream->data_len - stream->data_offset;
1717 err = 0;
1719 out:
1721 return err;
1725 /* Skip SIZE bytes of input data contained in buffer. */
1726 static int
1727 es_skip (estream_t stream, size_t size)
1729 int err;
1731 if (stream->data_offset + size > stream->data_len)
1733 errno = EINVAL;
1734 err = -1;
1736 else
1738 stream->data_offset += size;
1739 err = 0;
1742 return err;
1746 static int
1747 doreadline (estream_t ES__RESTRICT stream, size_t max_length,
1748 char *ES__RESTRICT *ES__RESTRICT line,
1749 size_t *ES__RESTRICT line_length)
1751 size_t space_left;
1752 size_t line_size;
1753 estream_t line_stream;
1754 char *line_new;
1755 void *line_stream_cookie;
1756 char *newline;
1757 unsigned char *data;
1758 size_t data_len;
1759 int err;
1761 line_new = NULL;
1762 line_stream = NULL;
1763 line_stream_cookie = NULL;
1765 err = es_func_mem_create (&line_stream_cookie, NULL, 0, 0,
1766 BUFFER_BLOCK_SIZE, 1,
1767 mem_realloc, mem_free,
1768 O_RDWR,
1770 if (err)
1771 goto out;
1773 err = es_create (&line_stream, line_stream_cookie, -1,
1774 estream_functions_mem, O_RDWR);
1775 if (err)
1776 goto out;
1778 space_left = max_length;
1779 line_size = 0;
1780 while (1)
1782 if (max_length && (space_left == 1))
1783 break;
1785 err = es_peek (stream, &data, &data_len);
1786 if (err || (! data_len))
1787 break;
1789 if (data_len > (space_left - 1))
1790 data_len = space_left - 1;
1792 newline = memchr (data, '\n', data_len);
1793 if (newline)
1795 data_len = (newline - (char *) data) + 1;
1796 err = es_write (line_stream, data, data_len, NULL);
1797 if (! err)
1799 space_left -= data_len;
1800 line_size += data_len;
1801 es_skip (stream, data_len);
1802 break;
1805 else
1807 err = es_write (line_stream, data, data_len, NULL);
1808 if (! err)
1810 space_left -= data_len;
1811 line_size += data_len;
1812 es_skip (stream, data_len);
1815 if (err)
1816 break;
1818 if (err)
1819 goto out;
1821 /* Complete line has been written to line_stream. */
1823 if ((max_length > 1) && (! line_size))
1825 stream->intern->indicators.eof = 1;
1826 goto out;
1829 err = es_seek (line_stream, 0, SEEK_SET, NULL);
1830 if (err)
1831 goto out;
1833 if (! *line)
1835 line_new = mem_alloc (line_size + 1);
1836 if (! line_new)
1838 err = -1;
1839 goto out;
1842 else
1843 line_new = *line;
1845 err = es_read (line_stream, line_new, line_size, NULL);
1846 if (err)
1847 goto out;
1849 line_new[line_size] = '\0';
1851 if (! *line)
1852 *line = line_new;
1853 if (line_length)
1854 *line_length = line_size;
1856 out:
1858 if (line_stream)
1859 es_destroy (line_stream);
1860 else if (line_stream_cookie)
1861 es_func_mem_destroy (line_stream_cookie);
1863 if (err)
1865 if (! *line)
1866 mem_free (line_new);
1867 stream->intern->indicators.err = 1;
1870 return err;
1874 /* Output fucntion used for estream_format. */
1875 static int
1876 print_writer (void *outfncarg, const char *buf, size_t buflen)
1878 estream_t stream = outfncarg;
1879 size_t nwritten;
1880 int rc;
1882 nwritten = 0;
1883 rc = es_writen (stream, buf, buflen, &nwritten);
1884 stream->intern->print_ntotal += nwritten;
1885 return rc;
1889 /* The core of our printf function. This is called in locked state. */
1890 static int
1891 es_print (estream_t ES__RESTRICT stream,
1892 const char *ES__RESTRICT format, va_list ap)
1894 int rc;
1896 stream->intern->print_ntotal = 0;
1897 rc = estream_format (print_writer, stream, format, ap);
1898 if (rc)
1899 return -1;
1900 return (int)stream->intern->print_ntotal;
1904 static void
1905 es_set_indicators (estream_t stream, int ind_err, int ind_eof)
1907 if (ind_err != -1)
1908 stream->intern->indicators.err = ind_err ? 1 : 0;
1909 if (ind_eof != -1)
1910 stream->intern->indicators.eof = ind_eof ? 1 : 0;
1914 static int
1915 es_get_indicator (estream_t stream, int ind_err, int ind_eof)
1917 int ret = 0;
1919 if (ind_err)
1920 ret = stream->intern->indicators.err;
1921 else if (ind_eof)
1922 ret = stream->intern->indicators.eof;
1924 return ret;
1928 static int
1929 es_set_buffering (estream_t ES__RESTRICT stream,
1930 char *ES__RESTRICT buffer, int mode, size_t size)
1932 int err;
1934 /* Flush or empty buffer depending on mode. */
1935 if (stream->flags.writing)
1937 err = es_flush (stream);
1938 if (err)
1939 goto out;
1941 else
1942 es_empty (stream);
1944 es_set_indicators (stream, -1, 0);
1946 /* Free old buffer in case that was allocated by this function. */
1947 if (stream->intern->deallocate_buffer)
1949 stream->intern->deallocate_buffer = 0;
1950 mem_free (stream->buffer);
1951 stream->buffer = NULL;
1954 if (mode == _IONBF)
1955 stream->buffer_size = 0;
1956 else
1958 void *buffer_new;
1960 if (buffer)
1961 buffer_new = buffer;
1962 else
1964 buffer_new = mem_alloc (size);
1965 if (! buffer_new)
1967 err = -1;
1968 goto out;
1972 stream->buffer = buffer_new;
1973 stream->buffer_size = size;
1974 if (! buffer)
1975 stream->intern->deallocate_buffer = 1;
1977 stream->intern->strategy = mode;
1978 err = 0;
1980 out:
1982 return err;
1986 static off_t
1987 es_offset_calculate (estream_t stream)
1989 off_t offset;
1991 offset = stream->intern->offset + stream->data_offset;
1992 if (offset < stream->unread_data_len)
1993 /* Offset undefined. */
1994 offset = 0;
1995 else
1996 offset -= stream->unread_data_len;
1998 return offset;
2002 static void
2003 es_opaque_ctrl (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque_new,
2004 void **ES__RESTRICT opaque_old)
2006 if (opaque_old)
2007 *opaque_old = stream->intern->opaque;
2008 if (opaque_new)
2009 stream->intern->opaque = opaque_new;
2013 static int
2014 es_get_fd (estream_t stream)
2016 return stream->intern->fd;
2021 /* API. */
2024 es_init (void)
2026 int err;
2028 err = es_init_do ();
2030 return err;
2033 estream_t
2034 es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
2036 unsigned int modeflags;
2037 int create_called;
2038 estream_t stream;
2039 void *cookie;
2040 int err;
2041 int fd;
2043 stream = NULL;
2044 cookie = NULL;
2045 create_called = 0;
2047 err = es_convert_mode (mode, &modeflags);
2048 if (err)
2049 goto out;
2051 err = es_func_file_create (&cookie, &fd, path, modeflags);
2052 if (err)
2053 goto out;
2055 create_called = 1;
2056 err = es_create (&stream, cookie, fd, estream_functions_file, modeflags);
2057 if (err)
2058 goto out;
2060 out:
2062 if (err && create_called)
2063 (*estream_functions_file.func_close) (cookie);
2065 return stream;
2069 estream_t
2070 es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
2071 unsigned int grow,
2072 func_realloc_t func_realloc, func_free_t func_free,
2073 const char *ES__RESTRICT mode)
2075 unsigned int modeflags;
2076 int create_called;
2077 estream_t stream;
2078 void *cookie;
2079 int err;
2081 cookie = 0;
2082 stream = NULL;
2083 create_called = 0;
2085 err = es_convert_mode (mode, &modeflags);
2086 if (err)
2087 goto out;
2089 err = es_func_mem_create (&cookie, data, data_n, data_len,
2090 BUFFER_BLOCK_SIZE, grow,
2091 func_realloc, func_free, modeflags, 0);
2092 if (err)
2093 goto out;
2095 create_called = 1;
2096 err = es_create (&stream, cookie, -1, estream_functions_mem, modeflags);
2098 out:
2100 if (err && create_called)
2101 (*estream_functions_mem.func_close) (cookie);
2103 return stream;
2107 estream_t
2108 es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode)
2110 unsigned int modeflags;
2111 estream_t stream = NULL;
2112 void *cookie = NULL;
2114 /* Memory streams are always read/write. We use MODE only to get
2115 the append flag. */
2116 if (es_convert_mode (mode, &modeflags))
2117 return NULL;
2118 modeflags |= O_RDWR;
2121 if (es_func_mem_create (&cookie, NULL, 0, 0,
2122 BUFFER_BLOCK_SIZE, 1,
2123 mem_realloc, mem_free, modeflags,
2124 memlimit))
2125 return NULL;
2127 if (es_create (&stream, cookie, -1, estream_functions_mem, modeflags))
2128 (*estream_functions_mem.func_close) (cookie);
2130 return stream;
2135 estream_t
2136 es_fopencookie (void *ES__RESTRICT cookie,
2137 const char *ES__RESTRICT mode,
2138 es_cookie_io_functions_t functions)
2140 unsigned int modeflags;
2141 estream_t stream;
2142 int err;
2144 stream = NULL;
2145 modeflags = 0;
2147 err = es_convert_mode (mode, &modeflags);
2148 if (err)
2149 goto out;
2151 err = es_create (&stream, cookie, -1, functions, modeflags);
2152 if (err)
2153 goto out;
2155 out:
2157 return stream;
2161 estream_t
2162 do_fdopen (int filedes, const char *mode, int no_close)
2164 unsigned int modeflags;
2165 int create_called;
2166 estream_t stream;
2167 void *cookie;
2168 int err;
2170 stream = NULL;
2171 cookie = NULL;
2172 create_called = 0;
2174 err = es_convert_mode (mode, &modeflags);
2175 if (err)
2176 goto out;
2178 err = es_func_fd_create (&cookie, filedes, modeflags, no_close);
2179 if (err)
2180 goto out;
2182 create_called = 1;
2183 err = es_create (&stream, cookie, filedes, estream_functions_fd, modeflags);
2185 out:
2187 if (err && create_called)
2188 (*estream_functions_fd.func_close) (cookie);
2190 return stream;
2193 estream_t
2194 es_fdopen (int filedes, const char *mode)
2196 return do_fdopen (filedes, mode, 0);
2199 /* A variant of es_fdopen which does not close FILEDES at the end. */
2200 estream_t
2201 es_fdopen_nc (int filedes, const char *mode)
2203 return do_fdopen (filedes, mode, 1);
2207 estream_t
2208 do_fpopen (FILE *fp, const char *mode, int no_close)
2210 unsigned int modeflags;
2211 int create_called;
2212 estream_t stream;
2213 void *cookie;
2214 int err;
2216 stream = NULL;
2217 cookie = NULL;
2218 create_called = 0;
2220 err = es_convert_mode (mode, &modeflags);
2221 if (err)
2222 goto out;
2224 fflush (fp);
2225 err = es_func_fp_create (&cookie, fp, modeflags, no_close);
2226 if (err)
2227 goto out;
2229 create_called = 1;
2230 err = es_create (&stream, cookie, fileno (fp), estream_functions_fp,
2231 modeflags);
2233 out:
2235 if (err && create_called)
2236 (*estream_functions_fp.func_close) (cookie);
2238 return stream;
2242 /* Create an estream from the stdio stream FP. This mechanism is
2243 useful in case the stdio streams have special properties and may
2244 not be mixed with fd based functions. This is for example the case
2245 under Windows where the 3 standard streams are associated with the
2246 console whereas a duped and fd-opened stream of one of this stream
2247 won't be associated with the console. As this messes things up it
2248 is easier to keep on using the standard I/O stream as a backend for
2249 estream. */
2250 estream_t
2251 es_fpopen (FILE *fp, const char *mode)
2253 return do_fpopen (fp, mode, 0);
2257 /* Same as es_fpopen but does not close FP at the end. */
2258 estream_t
2259 es_fpopen_nc (FILE *fp, const char *mode)
2261 return do_fpopen (fp, mode, 1);
2265 estream_t
2266 es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
2267 estream_t ES__RESTRICT stream)
2269 int err;
2271 if (path)
2273 unsigned int modeflags;
2274 int create_called;
2275 void *cookie;
2276 int fd;
2278 cookie = NULL;
2279 create_called = 0;
2281 ESTREAM_LOCK (stream);
2283 es_deinitialize (stream);
2285 err = es_convert_mode (mode, &modeflags);
2286 if (err)
2287 goto leave;
2289 err = es_func_file_create (&cookie, &fd, path, modeflags);
2290 if (err)
2291 goto leave;
2293 create_called = 1;
2294 es_initialize (stream, cookie, fd, estream_functions_file, modeflags);
2296 leave:
2298 if (err)
2300 if (create_called)
2301 es_func_fd_destroy (cookie);
2303 es_destroy (stream);
2304 stream = NULL;
2306 else
2307 ESTREAM_UNLOCK (stream);
2309 else
2311 /* FIXME? We don't support re-opening at the moment. */
2312 errno = EINVAL;
2313 es_deinitialize (stream);
2314 es_destroy (stream);
2315 stream = NULL;
2318 return stream;
2323 es_fclose (estream_t stream)
2325 int err;
2327 err = es_destroy (stream);
2329 return err;
2333 es_fileno_unlocked (estream_t stream)
2335 return es_get_fd (stream);
2339 void
2340 es_flockfile (estream_t stream)
2342 ESTREAM_LOCK (stream);
2347 es_ftrylockfile (estream_t stream)
2349 return ESTREAM_TRYLOCK (stream);
2353 void
2354 es_funlockfile (estream_t stream)
2356 ESTREAM_UNLOCK (stream);
2361 es_fileno (estream_t stream)
2363 int ret;
2365 ESTREAM_LOCK (stream);
2366 ret = es_fileno_unlocked (stream);
2367 ESTREAM_UNLOCK (stream);
2369 return ret;
2374 es_feof_unlocked (estream_t stream)
2376 return es_get_indicator (stream, 0, 1);
2381 es_feof (estream_t stream)
2383 int ret;
2385 ESTREAM_LOCK (stream);
2386 ret = es_feof_unlocked (stream);
2387 ESTREAM_UNLOCK (stream);
2389 return ret;
2394 es_ferror_unlocked (estream_t stream)
2396 return es_get_indicator (stream, 1, 0);
2401 es_ferror (estream_t stream)
2403 int ret;
2405 ESTREAM_LOCK (stream);
2406 ret = es_ferror_unlocked (stream);
2407 ESTREAM_UNLOCK (stream);
2409 return ret;
2413 void
2414 es_clearerr_unlocked (estream_t stream)
2416 es_set_indicators (stream, 0, 0);
2420 void
2421 es_clearerr (estream_t stream)
2423 ESTREAM_LOCK (stream);
2424 es_clearerr_unlocked (stream);
2425 ESTREAM_UNLOCK (stream);
2430 es_fflush (estream_t stream)
2432 int err;
2434 if (stream)
2436 ESTREAM_LOCK (stream);
2437 if (stream->flags.writing)
2438 err = es_flush (stream);
2439 else
2441 es_empty (stream);
2442 err = 0;
2444 ESTREAM_UNLOCK (stream);
2446 else
2447 err = es_list_iterate (es_fflush);
2449 return err ? EOF : 0;
2454 es_fseek (estream_t stream, long int offset, int whence)
2456 int err;
2458 ESTREAM_LOCK (stream);
2459 err = es_seek (stream, offset, whence, NULL);
2460 ESTREAM_UNLOCK (stream);
2462 return err;
2467 es_fseeko (estream_t stream, off_t offset, int whence)
2469 int err;
2471 ESTREAM_LOCK (stream);
2472 err = es_seek (stream, offset, whence, NULL);
2473 ESTREAM_UNLOCK (stream);
2475 return err;
2479 long int
2480 es_ftell (estream_t stream)
2482 long int ret;
2484 ESTREAM_LOCK (stream);
2485 ret = es_offset_calculate (stream);
2486 ESTREAM_UNLOCK (stream);
2488 return ret;
2492 off_t
2493 es_ftello (estream_t stream)
2495 off_t ret = -1;
2497 ESTREAM_LOCK (stream);
2498 ret = es_offset_calculate (stream);
2499 ESTREAM_UNLOCK (stream);
2501 return ret;
2505 void
2506 es_rewind (estream_t stream)
2508 ESTREAM_LOCK (stream);
2509 es_seek (stream, 0L, SEEK_SET, NULL);
2510 es_set_indicators (stream, 0, -1);
2511 ESTREAM_UNLOCK (stream);
2516 _es_getc_underflow (estream_t stream)
2518 int err;
2519 unsigned char c;
2520 size_t bytes_read;
2522 err = es_readn (stream, &c, 1, &bytes_read);
2524 return (err || (! bytes_read)) ? EOF : c;
2529 _es_putc_overflow (int c, estream_t stream)
2531 unsigned char d = c;
2532 int err;
2534 err = es_writen (stream, &d, 1, NULL);
2536 return err ? EOF : c;
2541 es_fgetc (estream_t stream)
2543 int ret;
2545 ESTREAM_LOCK (stream);
2546 ret = es_getc_unlocked (stream);
2547 ESTREAM_UNLOCK (stream);
2549 return ret;
2554 es_fputc (int c, estream_t stream)
2556 int ret;
2558 ESTREAM_LOCK (stream);
2559 ret = es_putc_unlocked (c, stream);
2560 ESTREAM_UNLOCK (stream);
2562 return ret;
2567 es_ungetc (int c, estream_t stream)
2569 unsigned char data = (unsigned char) c;
2570 size_t data_unread;
2572 ESTREAM_LOCK (stream);
2573 es_unreadn (stream, &data, 1, &data_unread);
2574 ESTREAM_UNLOCK (stream);
2576 return data_unread ? c : EOF;
2581 es_read (estream_t ES__RESTRICT stream,
2582 void *ES__RESTRICT buffer, size_t bytes_to_read,
2583 size_t *ES__RESTRICT bytes_read)
2585 int err;
2587 if (bytes_to_read)
2589 ESTREAM_LOCK (stream);
2590 err = es_readn (stream, buffer, bytes_to_read, bytes_read);
2591 ESTREAM_UNLOCK (stream);
2593 else
2594 err = 0;
2596 return err;
2601 es_write (estream_t ES__RESTRICT stream,
2602 const void *ES__RESTRICT buffer, size_t bytes_to_write,
2603 size_t *ES__RESTRICT bytes_written)
2605 int err;
2607 if (bytes_to_write)
2609 ESTREAM_LOCK (stream);
2610 err = es_writen (stream, buffer, bytes_to_write, bytes_written);
2611 ESTREAM_UNLOCK (stream);
2613 else
2614 err = 0;
2616 return err;
2620 size_t
2621 es_fread (void *ES__RESTRICT ptr, size_t size, size_t nitems,
2622 estream_t ES__RESTRICT stream)
2624 size_t ret, bytes;
2625 int err;
2627 if (size * nitems)
2629 ESTREAM_LOCK (stream);
2630 err = es_readn (stream, ptr, size * nitems, &bytes);
2631 ESTREAM_UNLOCK (stream);
2633 ret = bytes / size;
2635 else
2636 ret = 0;
2638 return ret;
2642 size_t
2643 es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t nitems,
2644 estream_t ES__RESTRICT stream)
2646 size_t ret, bytes;
2647 int err;
2649 if (size * nitems)
2651 ESTREAM_LOCK (stream);
2652 err = es_writen (stream, ptr, size * nitems, &bytes);
2653 ESTREAM_UNLOCK (stream);
2655 ret = bytes / size;
2657 else
2658 ret = 0;
2660 return ret;
2664 char *
2665 es_fgets (char *ES__RESTRICT buffer, int length, estream_t ES__RESTRICT stream)
2667 unsigned char *s = (unsigned char*)buffer;
2668 int c;
2670 if (!length)
2671 return NULL;
2673 c = EOF;
2674 ESTREAM_LOCK (stream);
2675 while (length > 1 && (c = es_getc_unlocked (stream)) != EOF && c != '\n')
2677 *s++ = c;
2678 length--;
2680 ESTREAM_UNLOCK (stream);
2682 if (c == EOF && s == (unsigned char*)buffer)
2683 return NULL; /* Nothing read. */
2685 if (c != EOF && length > 1)
2686 *s++ = c;
2688 *s = 0;
2689 return buffer;
2694 es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
2696 size_t length;
2697 int err;
2699 length = strlen (s);
2700 ESTREAM_LOCK (stream);
2701 err = es_writen (stream, s, length, NULL);
2702 ESTREAM_UNLOCK (stream);
2704 return err ? EOF : 0;
2708 ssize_t
2709 es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr, size_t *ES__RESTRICT n,
2710 estream_t ES__RESTRICT stream)
2712 char *line = NULL;
2713 size_t line_n = 0;
2714 int err;
2716 ESTREAM_LOCK (stream);
2717 err = doreadline (stream, 0, &line, &line_n);
2718 ESTREAM_UNLOCK (stream);
2719 if (err)
2720 goto out;
2722 if (*n)
2724 /* Caller wants us to use his buffer. */
2726 if (*n < (line_n + 1))
2728 /* Provided buffer is too small -> resize. */
2730 void *p;
2732 p = mem_realloc (*lineptr, line_n + 1);
2733 if (! p)
2734 err = -1;
2735 else
2737 if (*lineptr != p)
2738 *lineptr = p;
2742 if (! err)
2744 memcpy (*lineptr, line, line_n + 1);
2745 if (*n != line_n)
2746 *n = line_n;
2748 mem_free (line);
2750 else
2752 /* Caller wants new buffers. */
2753 *lineptr = line;
2754 *n = line_n;
2757 out:
2759 return err ? err : line_n;
2764 /* Same as fgets() but if the provided buffer is too short a larger
2765 one will be allocated. This is similar to getline. A line is
2766 considered a byte stream ending in a LF.
2768 If MAX_LENGTH is not NULL, it shall point to a value with the
2769 maximum allowed allocation.
2771 Returns the length of the line. EOF is indicated by a line of
2772 length zero. A truncated line is indicated my setting the value at
2773 MAX_LENGTH to 0. If the returned value is less then 0 not enough
2774 memory was enable or another error occurred; ERRNO is then set
2775 accordingly.
2777 If a line has been truncated, the file pointer is moved forward to
2778 the end of the line so that the next read starts with the next
2779 line. Note that MAX_LENGTH must be re-initialzied in this case.
2781 The caller initially needs to provide the address of a variable,
2782 initialized to NULL, at ADDR_OF_BUFFER and don't change this value
2783 anymore with the following invocations. LENGTH_OF_BUFFER should be
2784 the address of a variable, initialized to 0, which is also
2785 maintained by this function. Thus, both paramaters should be
2786 considered the state of this function.
2788 Note: The returned buffer is allocated with enough extra space to
2789 allow the caller to append a CR,LF,Nul. The buffer should be
2790 released using es_free.
2792 ssize_t
2793 es_read_line (estream_t stream,
2794 char **addr_of_buffer, size_t *length_of_buffer,
2795 size_t *max_length)
2797 int c;
2798 char *buffer = *addr_of_buffer;
2799 size_t length = *length_of_buffer;
2800 size_t nbytes = 0;
2801 size_t maxlen = max_length? *max_length : 0;
2802 char *p;
2804 if (!buffer)
2806 /* No buffer given - allocate a new one. */
2807 length = 256;
2808 buffer = mem_alloc (length);
2809 *addr_of_buffer = buffer;
2810 if (!buffer)
2812 *length_of_buffer = 0;
2813 if (max_length)
2814 *max_length = 0;
2815 return -1;
2817 *length_of_buffer = length;
2820 if (length < 4)
2822 /* This should never happen. If it does, the function has been
2823 called with wrong arguments. */
2824 errno = EINVAL;
2825 return -1;
2827 length -= 3; /* Reserve 3 bytes for CR,LF,EOL. */
2829 ESTREAM_LOCK (stream);
2830 p = buffer;
2831 while ((c = es_getc_unlocked (stream)) != EOF)
2833 if (nbytes == length)
2835 /* Enlarge the buffer. */
2836 if (maxlen && length > maxlen)
2838 /* We are beyond our limit: Skip the rest of the line. */
2839 while (c != '\n' && (c=es_getc_unlocked (stream)) != EOF)
2841 *p++ = '\n'; /* Always append a LF (we reserved some space). */
2842 nbytes++;
2843 if (max_length)
2844 *max_length = 0; /* Indicate truncation. */
2845 break; /* the while loop. */
2847 length += 3; /* Adjust for the reserved bytes. */
2848 length += length < 1024? 256 : 1024;
2849 *addr_of_buffer = mem_realloc (buffer, length);
2850 if (!*addr_of_buffer)
2852 int save_errno = errno;
2853 mem_free (buffer);
2854 *length_of_buffer = 0;
2855 if (max_length)
2856 *max_length = 0;
2857 ESTREAM_UNLOCK (stream);
2858 errno = save_errno;
2859 return -1;
2861 buffer = *addr_of_buffer;
2862 *length_of_buffer = length;
2863 length -= 3;
2864 p = buffer + nbytes;
2866 *p++ = c;
2867 nbytes++;
2868 if (c == '\n')
2869 break;
2871 *p = 0; /* Make sure the line is a string. */
2872 ESTREAM_UNLOCK (stream);
2874 return nbytes;
2877 /* Wrapper around free() to match the memory allocation system used
2878 by estream. Should be used for all buffers returned to the caller
2879 by libestream. */
2880 void
2881 es_free (void *a)
2883 mem_free (a);
2888 es_vfprintf (estream_t ES__RESTRICT stream, const char *ES__RESTRICT format,
2889 va_list ap)
2891 int ret;
2893 ESTREAM_LOCK (stream);
2894 ret = es_print (stream, format, ap);
2895 ESTREAM_UNLOCK (stream);
2897 return ret;
2901 static int
2902 es_fprintf_unlocked (estream_t ES__RESTRICT stream,
2903 const char *ES__RESTRICT format, ...)
2905 int ret;
2907 va_list ap;
2908 va_start (ap, format);
2909 ret = es_print (stream, format, ap);
2910 va_end (ap);
2912 return ret;
2917 es_fprintf (estream_t ES__RESTRICT stream,
2918 const char *ES__RESTRICT format, ...)
2920 int ret;
2922 va_list ap;
2923 va_start (ap, format);
2924 ESTREAM_LOCK (stream);
2925 ret = es_print (stream, format, ap);
2926 ESTREAM_UNLOCK (stream);
2927 va_end (ap);
2929 return ret;
2933 static int
2934 tmpfd (void)
2936 #ifdef HAVE_W32_SYSTEM
2937 int attempts, n;
2938 char buffer[MAX_PATH+9+12+1];
2939 char *name, *p;
2940 HANDLE file;
2941 int pid = GetCurrentProcessId ();
2942 unsigned int value;
2943 int i;
2945 n = GetTempPath (MAX_PATH+1, buffer);
2946 if (!n || n > MAX_PATH || strlen (buffer) > MAX_PATH)
2948 errno = ENOENT;
2949 return -1;
2951 p = buffer + strlen (buffer);
2952 strcpy (p, "_estream");
2953 p += 8;
2954 /* We try to create the directory but don't care about an error as
2955 it may already exist and the CreateFile would throw an error
2956 anyway. */
2957 CreateDirectory (buffer, NULL);
2958 *p++ = '\\';
2959 name = p;
2960 for (attempts=0; attempts < 10; attempts++)
2962 p = name;
2963 value = (GetTickCount () ^ ((pid<<16) & 0xffff0000));
2964 for (i=0; i < 8; i++)
2966 *p++ = tohex (((value >> 28) & 0x0f));
2967 value <<= 4;
2969 strcpy (p, ".tmp");
2970 file = CreateFile (buffer,
2971 GENERIC_READ | GENERIC_WRITE,
2973 NULL,
2974 CREATE_NEW,
2975 FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
2976 NULL);
2977 if (file != INVALID_HANDLE_VALUE)
2979 int fd = _open_osfhandle ((long)file, 0);
2980 if (fd == -1)
2982 CloseHandle (file);
2983 return -1;
2985 return fd;
2987 Sleep (1); /* One ms as this is the granularity of GetTickCount. */
2989 errno = ENOENT;
2990 return -1;
2991 #else /*!HAVE_W32_SYSTEM*/
2992 FILE *fp;
2993 int fp_fd;
2994 int fd;
2996 fp = NULL;
2997 fd = -1;
2999 fp = tmpfile ();
3000 if (! fp)
3001 goto out;
3003 fp_fd = fileno (fp);
3004 fd = dup (fp_fd);
3006 out:
3008 if (fp)
3009 fclose (fp);
3011 return fd;
3012 #endif /*!HAVE_W32_SYSTEM*/
3015 estream_t
3016 es_tmpfile (void)
3018 unsigned int modeflags;
3019 int create_called;
3020 estream_t stream;
3021 void *cookie;
3022 int err;
3023 int fd;
3025 create_called = 0;
3026 stream = NULL;
3027 modeflags = O_RDWR | O_TRUNC | O_CREAT;
3028 cookie = NULL;
3030 fd = tmpfd ();
3031 if (fd == -1)
3033 err = -1;
3034 goto out;
3037 err = es_func_fd_create (&cookie, fd, modeflags, 0);
3038 if (err)
3039 goto out;
3041 create_called = 1;
3042 err = es_create (&stream, cookie, fd, estream_functions_fd, modeflags);
3044 out:
3046 if (err)
3048 if (create_called)
3049 es_func_fd_destroy (cookie);
3050 else if (fd != -1)
3051 close (fd);
3052 stream = NULL;
3055 return stream;
3060 es_setvbuf (estream_t ES__RESTRICT stream,
3061 char *ES__RESTRICT buf, int type, size_t size)
3063 int err;
3065 if (((type == _IOFBF) || (type == _IOLBF) || (type == _IONBF))
3066 && (! ((! size) && (type != _IONBF))))
3068 ESTREAM_LOCK (stream);
3069 err = es_set_buffering (stream, buf, type, size);
3070 ESTREAM_UNLOCK (stream);
3072 else
3074 errno = EINVAL;
3075 err = -1;
3078 return err;
3082 void
3083 es_setbuf (estream_t ES__RESTRICT stream, char *ES__RESTRICT buf)
3085 ESTREAM_LOCK (stream);
3086 es_set_buffering (stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
3087 ESTREAM_UNLOCK (stream);
3090 void
3091 es_opaque_set (estream_t stream, void *opaque)
3093 ESTREAM_LOCK (stream);
3094 es_opaque_ctrl (stream, opaque, NULL);
3095 ESTREAM_UNLOCK (stream);
3099 void *
3100 es_opaque_get (estream_t stream)
3102 void *opaque;
3104 ESTREAM_LOCK (stream);
3105 es_opaque_ctrl (stream, NULL, &opaque);
3106 ESTREAM_UNLOCK (stream);
3108 return opaque;
3111 /* Print a BUFFER to STREAM while replacing all control characters and
3112 the characters in DELIMITERS by standard C escape sequences.
3113 Returns 0 on success or -1 on error. If BYTES_WRITTEN is not NULL
3114 the number of bytes actually written are stored at this
3115 address. */
3116 int
3117 es_write_sanitized (estream_t ES__RESTRICT stream,
3118 const void * ES__RESTRICT buffer, size_t length,
3119 const char * delimiters,
3120 size_t * ES__RESTRICT bytes_written)
3122 const unsigned char *p = buffer;
3123 size_t count = 0;
3124 int ret;
3126 ESTREAM_LOCK (stream);
3127 for (; length; length--, p++, count++)
3129 if (*p < 0x20
3130 || *p == 0x7f
3131 || (delimiters
3132 && (strchr (delimiters, *p) || *p == '\\')))
3134 es_putc_unlocked ('\\', stream);
3135 count++;
3136 if (*p == '\n')
3138 es_putc_unlocked ('n', stream);
3139 count++;
3141 else if (*p == '\r')
3143 es_putc_unlocked ('r', stream);
3144 count++;
3146 else if (*p == '\f')
3148 es_putc_unlocked ('f', stream);
3149 count++;
3151 else if (*p == '\v')
3153 es_putc_unlocked ('v', stream);
3154 count++;
3156 else if (*p == '\b')
3158 es_putc_unlocked ('b', stream);
3159 count++;
3161 else if (!*p)
3163 es_putc_unlocked('0', stream);
3164 count++;
3166 else
3168 es_fprintf_unlocked (stream, "x%02x", *p);
3169 count += 3;
3172 else
3174 es_putc_unlocked (*p, stream);
3175 count++;
3179 if (bytes_written)
3180 *bytes_written = count;
3181 ret = es_ferror_unlocked (stream)? -1 : 0;
3182 ESTREAM_UNLOCK (stream);
3184 return ret;
3188 /* Write LENGTH bytes of BUFFER to STREAM as a hex encoded string.
3189 RESERVED must be 0. Returns 0 on success or -1 on error. If
3190 BYTES_WRITTEN is not NULL the number of bytes actually written are
3191 stored at this address. */
3193 es_write_hexstring (estream_t ES__RESTRICT stream,
3194 const void *ES__RESTRICT buffer, size_t length,
3195 int reserved, size_t *ES__RESTRICT bytes_written )
3197 int ret;
3198 const unsigned char *s;
3199 size_t count = 0;
3201 (void)reserved;
3203 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
3205 if (!length)
3206 return 0;
3208 ESTREAM_LOCK (stream);
3210 for (s = buffer; length; s++, length--)
3212 es_putc_unlocked ( tohex ((*s>>4)&15), stream);
3213 es_putc_unlocked ( tohex (*s&15), stream);
3214 count += 2;
3217 if (bytes_written)
3218 *bytes_written = count;
3219 ret = es_ferror_unlocked (stream)? -1 : 0;
3221 ESTREAM_UNLOCK (stream);
3223 return ret;
3225 #undef tohex
3230 #ifdef GNUPG_MAJOR_VERSION
3231 /* Special estream function to print an UTF8 string in the native
3232 encoding. The interface is the same as es_write_sanitized, however
3233 only one delimiter may be supported.
3235 THIS IS NOT A STANDARD ESTREAM FUNCTION AND ONLY USED BY GNUPG!. */
3237 es_write_sanitized_utf8_buffer (estream_t stream,
3238 const void *buffer, size_t length,
3239 const char *delimiters, size_t *bytes_written)
3241 const char *p = buffer;
3242 size_t i;
3244 /* We can handle plain ascii simpler, so check for it first. */
3245 for (i=0; i < length; i++ )
3247 if ( (p[i] & 0x80) )
3248 break;
3250 if (i < length)
3252 int delim = delimiters? *delimiters : 0;
3253 char *buf;
3254 int ret;
3256 /*(utf8 conversion already does the control character quoting). */
3257 buf = utf8_to_native (p, length, delim);
3258 if (bytes_written)
3259 *bytes_written = strlen (buf);
3260 ret = es_fputs (buf, stream);
3261 xfree (buf);
3262 return ret == EOF? ret : (int)i;
3264 else
3265 return es_write_sanitized (stream, p, length, delimiters, bytes_written);
3267 #endif /*GNUPG_MAJOR_VERSION*/