From a55b52ca815a7f7dd63ea55ddcccd943c0ed59b8 Mon Sep 17 00:00:00 2001 From: jmjatlanta Date: Wed, 20 Sep 2017 10:26:24 -0500 Subject: [PATCH] Addition of memstream for osx and bsd --- include/libp2p/os/memstream.h | 11 +++ os/Makefile | 2 +- os/memstream.c | 177 ++++++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 include/libp2p/os/memstream.h create mode 100644 os/memstream.c diff --git a/include/libp2p/os/memstream.h b/include/libp2p/os/memstream.h new file mode 100644 index 0000000..8c70f25 --- /dev/null +++ b/include/libp2p/os/memstream.h @@ -0,0 +1,11 @@ +#if defined(__linux__) +# include +#endif + +#include + +#if _POSIX_C_SOURCE < 200809L + +FILE *open_memstream(char **ptr, size_t *sizeloc); + +#endif /* _POSIX_C_SOURCE < 200809L */ diff --git a/os/Makefile b/os/Makefile index 6dcc0e6..6e1faaf 100644 --- a/os/Makefile +++ b/os/Makefile @@ -2,7 +2,7 @@ CC = gcc CFLAGS = -O0 -I../include -I../../c-protobuf -I../../c-multihash/include -I../../c-multiaddr/include -g3 LFLAGS = DEPS = -OBJS = utils.o +OBJS = utils.o memstream.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) diff --git a/os/memstream.c b/os/memstream.c new file mode 100644 index 0000000..523b9ba --- /dev/null +++ b/os/memstream.c @@ -0,0 +1,177 @@ +/* Compile this file and link the object with your program. On a recent + * GNU/Linux machine the object file will be empty. On anything derived from + * 4.4BSD (Darwin, the Three BSDs, etc.) it will contain an implementation of + * open_memstream() as described in the POSIX and Linux manual pages. On + * anything else it will probably cause a compilation error. + * + * ---------------------------------------------------------------------------- + * + * OPEN_MEMSTREAM(3) BSD and Linux Library Functions OPEN_MEMSTREAM(3) + * + * SYNOPSIS + * #include "memstream.h" + * + * FILE *open_memstream(char **bufp, size_t *sizep); + * + * DESCRIPTION + * The open_memstream() function opens a stream for writing to a buffer. + * The buffer is dynamically allocated (as with malloc(3)), and + * automatically grows as required. After closing the stream, the caller + * should free(3) this buffer. + * + * When the stream is closed (fclose(3)) or flushed (fflush(3)), the + * locations pointed to by bufp and sizep are updated to contain, + * respectively, a pointer to the buffer and the current size of the + * buffer. These values remain valid only as long as the caller performs + * no further output on the stream. If further output is performed, then + * the stream must again be flushed before trying to access these + * variables. + * + * A null byte is maintained at the end of the buffer. This byte is not + * included in the size value stored at sizep. + * + * The stream's file position can be changed with fseek(3) or fseeko(3). + * Moving the file position past the end of the data already written fills + * the intervening space with zeros. + * + * RETURN VALUE + * Upon successful completion open_memstream() returns a FILE pointer. + * Otherwise, NULL is returned and errno is set to indicate the error. + * + * CONFORMING TO + * POSIX.1-2008 + * + * ---------------------------------------------------------------------------- + */ + +#include "libp2p/os/memstream.h" + +#if _POSIX_C_SOURCE < 200809L + +#include +#include +#include +#include +#include + +#define min(X, Y) (((X) < (Y)) ? (X) : (Y)) + +struct memstream +{ + int position; + int size; + int capacity; + char *contents; + char **ptr; + size_t *sizeloc; +}; + +#if MEMSTREAM_DEBUG + static void memstream_print(struct memstream *ms) + { + printf("memstream %p {", ms); + printf(" %i", ms->position); + printf(" %i", ms->size); + printf(" %i", ms->capacity); + printf(" %p", ms->contents); + printf(" }\n"); + } +# define memstream_info(ARGS) printf ARGS +#else +# define memstream_print(ms) +# define memstream_info(ARGS) +#endif + +#define memstream_check(MS) if (!(MS)->contents) { errno= ENOMEM; return -1; } + +static int memstream_grow(struct memstream *ms, int minsize) +{ + int newcap= ms->capacity * 2; memstream_check(ms); + while (newcap <= minsize) newcap *= 2; memstream_info(("grow %p to %i\n", ms, newcap)); + ms->contents= realloc(ms->contents, newcap); + if (!ms->contents) return -1; /* errno == ENOMEM */ + memset(ms->contents + ms->capacity, 0, newcap - ms->capacity); + ms->capacity= newcap; + *ms->ptr= ms->contents; /* size has not changed */ + return 0; +} + +static int memstream_read(void *cookie, char *buf, int count) +{ + struct memstream *ms= (struct memstream *)cookie; memstream_check(ms); + int n= min(ms->size - ms->position, count); memstream_info(("memstream_read %p %i\n", ms, count)); + if (n < 1) return 0; + memcpy(buf, ms->contents, n); + ms->position += n; memstream_print(ms); + return n; +} + +static int memstream_write(void *cookie, const char *buf, int count) +{ + struct memstream *ms= (struct memstream *)cookie; memstream_check(ms); + if (ms->capacity <= ms->position + count) + if (memstream_grow(ms, ms->position + count) < 0) /* errno == ENOMEM */ + return -1; + memcpy(ms->contents + ms->position, buf, count); memstream_info(("memstream_write %p %i\n", ms, count)); + ms->position += count; + if (ms->size < ms->position) *ms->sizeloc= ms->size= ms->position; memstream_print(ms); + assert(ms->size < ms->capacity); + assert(ms->contents[ms->size] == 0); + return count; +} + +static fpos_t memstream_seek(void *cookie, fpos_t offset, int whence) +{ + struct memstream *ms= (struct memstream *)cookie; + fpos_t pos= 0; memstream_check(ms); + memstream_info(("memstream_seek %p %i %i\n", ms, (int)offset, whence)); + switch (whence) { + case SEEK_SET: pos= offset; break; + case SEEK_CUR: pos= ms->position + offset; break; + case SEEK_END: pos= ms->size + offset; break; + default: errno= EINVAL; return -1; + } + if (pos >= ms->capacity) memstream_grow(ms, pos); + ms->position= pos; + if (ms->size < ms->position) *ms->sizeloc= ms->size= ms->position; memstream_print(ms); memstream_info(("=> %i\n", (int)pos)); + assert(ms->size < ms->capacity && ms->contents[ms->size] == 0); + return pos; +} + +static int memstream_close(void *cookie) +{ + struct memstream *ms= (struct memstream *)cookie; if (!ms->contents) { free(ms); errno= ENOMEM; return -1; } + ms->size= min(ms->size, ms->position); + *ms->ptr= ms->contents; + *ms->sizeloc= ms->size; assert(ms->size < ms->capacity); + ms->contents[ms->size]= 0; + free(ms); + return 0; +} + +FILE *open_memstream(char **ptr, size_t *sizeloc) +{ + if (ptr && sizeloc) { + struct memstream *ms= calloc(1, sizeof(struct memstream)); + FILE *fp= 0; if (!ms) return 0; /* errno == ENOMEM */ + ms->position= ms->size= 0; + ms->capacity= 4096; + ms->contents= calloc(ms->capacity, 1); if (!ms->contents) { free(ms); return 0; } /* errno == ENOMEM */ + ms->ptr= ptr; + ms->sizeloc= sizeloc; + memstream_print(ms); + fp= funopen(ms, memstream_read, memstream_write, memstream_seek, memstream_close); + if (!fp) { + free(ms->contents); + free(ms); + return 0; /* errno set by funopen */ + } + *ptr= ms->contents; + *sizeloc= ms->size; + return fp; + } + errno= EINVAL; + return 0; +} + +#endif /* _POSIX_C_SOURCE < 200809L */