diff options
Diffstat (limited to 'sysutils/mcelog/files/memstream.c')
-rw-r--r-- | sysutils/mcelog/files/memstream.c | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/sysutils/mcelog/files/memstream.c b/sysutils/mcelog/files/memstream.c new file mode 100644 index 000000000000..20cbf29b472c --- /dev/null +++ b/sysutils/mcelog/files/memstream.c @@ -0,0 +1,133 @@ +/* Use funopen(3) to provide open_memstream(3) like functionality. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +struct memstream { + char **cp; + size_t *lenp; + size_t offset; +}; + +FILE * +open_memstream(char **cp, size_t *lenp); + +static void +memstream_grow(struct memstream *ms, size_t newsize) +{ + char *buf; + + if (newsize > *ms->lenp) { + buf = realloc(*ms->cp, newsize + 1); + if (buf != NULL) { +#ifdef DEBUG + fprintf(stderr, "MS: %p growing from %zd to %zd\n", + ms, *ms->lenp, newsize); +#endif + memset(buf + *ms->lenp + 1, 0, newsize - *ms->lenp); + *ms->cp = buf; + *ms->lenp = newsize; + } + } +} + +static int +memstream_read(void *cookie, char *buf, int len) +{ + struct memstream *ms; + int tocopy; + + ms = cookie; + memstream_grow(ms, ms->offset + len); + tocopy = *ms->lenp - ms->offset; + if (len < tocopy) + tocopy = len; + memcpy(buf, *ms->cp + ms->offset, tocopy); + ms->offset += tocopy; +#ifdef DEBUG + fprintf(stderr, "MS: read(%p, %d) = %d\n", ms, len, tocopy); +#endif + return (tocopy); +} + +static int +memstream_write(void *cookie, const char *buf, int len) +{ + struct memstream *ms; + int tocopy; + + ms = cookie; + memstream_grow(ms, ms->offset + len); + tocopy = *ms->lenp - ms->offset; + if (len < tocopy) + tocopy = len; + memcpy(*ms->cp + ms->offset, buf, tocopy); + ms->offset += tocopy; +#ifdef DEBUG + fprintf(stderr, "MS: write(%p, %d) = %d\n", ms, len, tocopy); +#endif + return (tocopy); +} + +static fpos_t +memstream_seek(void *cookie, fpos_t pos, int whence) +{ + struct memstream *ms; +#ifdef DEBUG + size_t old; +#endif + + ms = cookie; +#ifdef DEBUG + old = ms->offset; +#endif + switch (whence) { + case SEEK_SET: + ms->offset = pos; + break; + case SEEK_CUR: + ms->offset += pos; + break; + case SEEK_END: + ms->offset = *ms->lenp + pos; + break; + } +#ifdef DEBUG + fprintf(stderr, "MS: seek(%p, %zd, %d) %zd -> %zd\n", ms, pos, whence, + old, ms->offset); +#endif + return (ms->offset); +} + +static int +memstream_close(void *cookie) +{ + + free(cookie); + return (0); +} + +FILE * +open_memstream(char **cp, size_t *lenp) +{ + struct memstream *ms; + int save_errno; + FILE *fp; + + *cp = NULL; + *lenp = 0; + ms = malloc(sizeof(*ms)); + ms->cp = cp; + ms->lenp = lenp; + ms->offset = 0; + fp = funopen(ms, memstream_read, memstream_write, memstream_seek, + memstream_close); + if (fp == NULL) { + save_errno = errno; + free(ms); + errno = save_errno; + } + return (fp); +} |