diff options
-rw-r--r-- | configure.ac | 9 | ||||
-rw-r--r-- | src/input.h | 6 | ||||
-rw-r--r-- | src/stream.c | 78 |
3 files changed, 85 insertions, 8 deletions
diff --git a/configure.ac b/configure.ac index 298da146..11b5d00a 100644 --- a/configure.ac +++ b/configure.ac @@ -406,6 +406,15 @@ AC_SUBST(EXTERNAL_COLM) AC_SUBST(EXTERNAL_INC) AC_SUBST(EXTERNAL_LIBS) +dnl Check for fopencookie. If available, we will use to avoid leaking FILE structs. +dnl The result of an fdopen cannot be closed without also closing the fd, so we +dnl make our own FILE type. +AC_CHECK_FUNC(fopencookie, + [AC_DEFINE([HAVE_FOPENCOOKIE], [1], [have fopencookie])], + [] +) + + dnl dnl Wrap up. dnl diff --git a/src/input.h b/src/input.h index 8cb20088..1d86a11b 100644 --- a/src/input.h +++ b/src/input.h @@ -193,6 +193,12 @@ struct stream_impl_data char *name; FILE *file; + // There is one condition when we don't want to close the FILE struct. If + // there is no fopencookie available, we need to use fdopen to wrap FD 0, 1 + // and 2. However, closing those also closes the file descriptor, and when + // a colm program is embedded in a bigger program, we don't want that. + int no_file_close; + struct colm_str_collect *collect; int consumed; diff --git a/src/stream.c b/src/stream.c index 69cbd0ad..0afde365 100644 --- a/src/stream.c +++ b/src/stream.c @@ -20,6 +20,13 @@ * SOFTWARE. */ +#include "config.h" + +#ifdef HAVE_FOPENCOOKIE +#define _GNU_SOURCE +#include <sys/types.h> +#endif + #include <colm/input.h> #include <stdio.h> @@ -42,6 +49,57 @@ DEF_STREAM_FUNCS( stream_funcs_data, stream_impl_data ); extern struct stream_funcs_data file_funcs; extern struct stream_funcs_data accum_funcs; +#ifdef HAVE_FOPENCOOKIE + +struct colm_file_cookie +{ + int fd; +}; + +static ssize_t cfc_read(void *cookie, char *buf, size_t size) +{ + return read( ((struct colm_file_cookie*)cookie)->fd, buf, size ); +} + +static ssize_t cfc_write(void *cookie, const char *buf, size_t size) +{ + return write( ((struct colm_file_cookie*)cookie)->fd, buf, size ); +} + +static int cfc_seek(void *cookie, off_t *offset, int whence) +{ + return -1; +} + +static int cfc_close(void *cookie) +{ + free(cookie); + return 0; +} + +FILE *colm_fd_open( int fd, const char *mode ) +{ + cookie_io_functions_t cf = { + cfc_read, + cfc_write, + cfc_seek, + cfc_close, + }; + + struct colm_file_cookie *cfc = malloc(sizeof(struct colm_file_cookie)); + cfc->fd = fd; + return fopencookie( cfc, mode, cf ); +} + +#else + +FILE *colm_fd_open( int fd, const char *mode ) +{ + return fdopen( fd, mode ); +} + +#endif + void stream_impl_push_line( struct stream_impl_data *ss, int ll ) { if ( ss->line_len == 0 ) { @@ -94,9 +152,7 @@ static bool loc_set( location_t *loc ) static void close_stream_file( FILE *file ) { - if ( file != stdin && file != stdout && file != stderr && - fileno(file) != 0 && fileno( file) != 1 && fileno(file) != 2 ) - { + if ( file != stdin && file != stdout && file != stderr ) { fclose( file ); } } @@ -349,7 +405,7 @@ int data_undo_append_data( struct colm_program *prg, struct stream_impl_data *si static void data_destructor( program_t *prg, tree_t **sp, struct stream_impl_data *si ) { - if ( si->file != 0 ) + if ( si->file != 0 && !si->no_file_close ) close_stream_file( si->file ); if ( si->collect != 0 ) { @@ -394,10 +450,10 @@ static void data_flush_stream( struct colm_program *prg, struct stream_impl_data static void data_close_stream( struct colm_program *prg, struct stream_impl_data *si ) { - if ( si->file != 0 ) { + if ( si->file != 0 && !si->no_file_close ) close_stream_file( si->file ); - si->file = 0; - } + + si->file = 0; } static int data_get_option( struct colm_program *prg, struct stream_impl_data *si, int option ) @@ -696,7 +752,13 @@ static struct stream_impl *colm_impl_new_fd( char *name, long fd ) malloc(sizeof(struct stream_impl_data)); si_data_init( si, name ); si->funcs = (struct stream_funcs*)&file_funcs; - si->file = fdopen( fd, ( fd == 0 ) ? "r" : "w" ); + + const char *mode = ( fd == 0 ) ? "r" : "w"; + si->file = colm_fd_open( fd, mode ); +#ifndef HAVE_FOPENCOOKIE + if ( fd == 0 || fd == 1 || fd == 2 ) + si->no_file_close = 1; +#endif return (struct stream_impl*)si; } |