diff options
author | Elliott Hughes <enh@google.com> | 2014-08-20 16:10:49 -0700 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2014-08-20 17:03:46 -0700 |
commit | 6b841db2baa24ffcf2a4e5f975d1d07f1699b918 (patch) | |
tree | af58fa1f4b5fa777f47e9ef797c50cff964b7046 /libc/upstream-openbsd | |
parent | b6ed54076abdd337150d7a92a661247b69d26cb4 (diff) | |
download | bionic-6b841db2baa24ffcf2a4e5f975d1d07f1699b918.zip bionic-6b841db2baa24ffcf2a4e5f975d1d07f1699b918.tar.gz bionic-6b841db2baa24ffcf2a4e5f975d1d07f1699b918.tar.bz2 |
Add POSIX-2008 fmemopen, open_memstream, and open_wmemstream.
Bug: 17164505
Change-Id: I59e28a08ff8b6ab632230b11a5807cfd5278aeb5
Diffstat (limited to 'libc/upstream-openbsd')
-rw-r--r-- | libc/upstream-openbsd/lib/libc/stdio/fmemopen.c | 183 | ||||
-rw-r--r-- | libc/upstream-openbsd/lib/libc/stdio/open_memstream.c | 158 | ||||
-rw-r--r-- | libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c | 169 |
3 files changed, 510 insertions, 0 deletions
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fmemopen.c b/libc/upstream-openbsd/lib/libc/stdio/fmemopen.c new file mode 100644 index 0000000..8cda047 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/stdio/fmemopen.c @@ -0,0 +1,183 @@ +/* $OpenBSD: fmemopen.c,v 1.2 2013/03/27 15:06:25 mpi Exp $ */ + +/* + * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org> + * Copyright (c) 2009 Ted Unangst + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "local.h" + +struct state { + char *string; /* actual stream */ + size_t pos; /* current position */ + size_t size; /* allocated size */ + size_t len; /* length of the data */ + int update; /* open for update */ +}; + +static int +fmemopen_read(void *v, char *b, int l) +{ + struct state *st = v; + int i; + + for (i = 0; i < l && i + st->pos < st->len; i++) + b[i] = st->string[st->pos + i]; + st->pos += i; + + return (i); +} + +static int +fmemopen_write(void *v, const char *b, int l) +{ + struct state *st = v; + int i; + + for (i = 0; i < l && i + st->pos < st->size; i++) + st->string[st->pos + i] = b[i]; + st->pos += i; + + if (st->pos >= st->len) { + st->len = st->pos; + + if (st->len < st->size) + st->string[st->len] = '\0'; + else if (!st->update) + st->string[st->size - 1] = '\0'; + } + + return (i); +} + +static fpos_t +fmemopen_seek(void *v, fpos_t off, int whence) +{ + struct state *st = v; + ssize_t base = 0; + + switch (whence) { + case SEEK_SET: + break; + case SEEK_CUR: + base = st->pos; + break; + case SEEK_END: + base = st->len; + break; + } + + if (off > st->size - base || off < -base) { + errno = EOVERFLOW; + return (-1); + } + + st->pos = base + off; + + return (st->pos); +} + +static int +fmemopen_close(void *v) +{ + free(v); + + return (0); +} + +static int +fmemopen_close_free(void *v) +{ + struct state *st = v; + + free(st->string); + free(st); + + return (0); +} + +FILE * +fmemopen(void *buf, size_t size, const char *mode) +{ + struct state *st; + FILE *fp; + int flags, oflags; + + if (size == 0) { + errno = EINVAL; + return (NULL); + } + + if ((flags = __sflags(mode, &oflags)) == 0) { + errno = EINVAL; + return (NULL); + } + + if (buf == NULL && ((oflags & O_RDWR) == 0)) { + errno = EINVAL; + return (NULL); + } + + if ((st = malloc(sizeof(*st))) == NULL) + return (NULL); + + if ((fp = __sfp()) == NULL) { + free(st); + return (NULL); + } + + st->pos = 0; + st->len = (oflags & O_WRONLY) ? 0 : size; + st->size = size; + st->update = oflags & O_RDWR; + + if (buf == NULL) { + if ((st->string = malloc(size)) == NULL) { + free(st); + fp->_flags = 0; + return (NULL); + } + *st->string = '\0'; + } else { + st->string = (char *)buf; + + if (oflags & O_TRUNC) + *st->string = '\0'; + + if (oflags & O_APPEND) { + char *p; + + if ((p = memchr(st->string, '\0', size)) != NULL) + st->pos = st->len = (p - st->string); + else + st->pos = st->len = size; + } + } + + fp->_flags = (short)flags; + fp->_file = -1; + fp->_cookie = (void *)st; + fp->_read = (flags & __SWR) ? NULL : fmemopen_read; + fp->_write = (flags & __SRD) ? NULL : fmemopen_write; + fp->_seek = fmemopen_seek; + fp->_close = (buf == NULL) ? fmemopen_close_free : fmemopen_close; + + return (fp); +} diff --git a/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c b/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c new file mode 100644 index 0000000..4610535 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c @@ -0,0 +1,158 @@ +/* $OpenBSD: open_memstream.c,v 1.3 2013/04/03 03:11:53 guenther Exp $ */ + +/* + * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "local.h" + +struct state { + char *string; /* actual stream */ + char **pbuf; /* point to the stream */ + size_t *psize; /* point to min(pos, len) */ + size_t pos; /* current position */ + size_t size; /* number of allocated char */ + size_t len; /* length of the data */ +}; + +static int +memstream_write(void *v, const char *b, int l) +{ + struct state *st = v; + char *p; + size_t i, end; + + end = (st->pos + l); + + if (end >= st->size) { + /* 1.6 is (very) close to the golden ratio. */ + size_t sz = st->size * 8 / 5; + + if (sz < end + 1) + sz = end + 1; + p = realloc(st->string, sz); + if (!p) + return (-1); + bzero(p + st->size, sz - st->size); + *st->pbuf = st->string = p; + st->size = sz; + } + + for (i = 0; i < l; i++) + st->string[st->pos + i] = b[i]; + st->pos += l; + + if (st->pos > st->len) { + st->len = st->pos; + st->string[st->len] = '\0'; + } + + *st->psize = st->pos; + + return (i); +} + +static fpos_t +memstream_seek(void *v, fpos_t off, int whence) +{ + struct state *st = v; + ssize_t base = 0; + + switch (whence) { + case SEEK_SET: + break; + case SEEK_CUR: + base = st->pos; + break; + case SEEK_END: + base = st->len; + break; + } + + if (off > SIZE_MAX - base || off < -base) { + errno = EOVERFLOW; + return (-1); + } + + st->pos = base + off; + *st->psize = MIN(st->pos, st->len); + + return (st->pos); +} + +static int +memstream_close(void *v) +{ + struct state *st = v; + + free(st); + + return (0); +} + +FILE * +open_memstream(char **pbuf, size_t *psize) +{ + struct state *st; + FILE *fp; + + if (pbuf == NULL || psize == NULL) { + errno = EINVAL; + return (NULL); + } + + if ((st = malloc(sizeof(*st))) == NULL) + return (NULL); + + if ((fp = __sfp()) == NULL) { + free(st); + return (NULL); + } + + st->size = BUFSIZ; + if ((st->string = calloc(1, st->size)) == NULL) { + free(st); + fp->_flags = 0; + return (NULL); + } + + *st->string = '\0'; + st->pos = 0; + st->len = 0; + st->pbuf = pbuf; + st->psize = psize; + + *pbuf = st->string; + *psize = st->len; + + fp->_flags = __SWR; + fp->_file = -1; + fp->_cookie = st; + fp->_read = NULL; + fp->_write = memstream_write; + fp->_seek = memstream_seek; + fp->_close = memstream_close; + _SET_ORIENTATION(fp, -1); + + return (fp); +} diff --git a/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c b/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c new file mode 100644 index 0000000..9414187 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c @@ -0,0 +1,169 @@ +/* $OpenBSD: open_wmemstream.c,v 1.3 2014/03/06 07:28:21 gerhard Exp $ */ + +/* + * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wchar.h> +#include "local.h" + +struct state { + wchar_t *string; /* actual stream */ + wchar_t **pbuf; /* point to the stream */ + size_t *psize; /* point to min(pos, len) */ + size_t pos; /* current position */ + size_t size; /* number of allocated wchar_t */ + size_t len; /* length of the data */ + mbstate_t mbs; /* conversion state of the stream */ +}; + +static int +wmemstream_write(void *v, const char *b, int l) +{ + struct state *st = v; + wchar_t *p; + size_t nmc, len, end; + + end = (st->pos + l); + + if (end >= st->size) { + /* 1.6 is (very) close to the golden ratio. */ + size_t sz = st->size * 8 / 5; + + if (sz < end + 1) + sz = end + 1; + p = realloc(st->string, sz * sizeof(wchar_t)); + if (!p) + return (-1); + bzero(p + st->size, (sz - st->size) * sizeof(wchar_t)); + *st->pbuf = st->string = p; + st->size = sz; + } + + nmc = (st->size - st->pos) * sizeof(wchar_t); + len = mbsnrtowcs(st->string + st->pos, &b, nmc, l, &st->mbs); + if (len == (size_t)-1) + return (-1); + st->pos += len; + + if (st->pos > st->len) { + st->len = st->pos; + st->string[st->len] = L'\0'; + } + + *st->psize = st->pos; + + return (len); +} + +static fpos_t +wmemstream_seek(void *v, fpos_t off, int whence) +{ + struct state *st = v; + ssize_t base = 0; + + switch (whence) { + case SEEK_SET: + break; + case SEEK_CUR: + base = st->pos; + break; + case SEEK_END: + base = st->len; + break; + } + + if (off > (SIZE_MAX / sizeof(wchar_t)) - base || off < -base) { + errno = EOVERFLOW; + return (-1); + } + + /* + * XXX Clearing mbs here invalidates shift state for state- + * dependent encodings, but they are not (yet) supported. + */ + bzero(&st->mbs, sizeof(st->mbs)); + + st->pos = base + off; + *st->psize = MIN(st->pos, st->len); + + return (st->pos); +} + +static int +wmemstream_close(void *v) +{ + struct state *st = v; + + free(st); + + return (0); +} + +FILE * +open_wmemstream(wchar_t **pbuf, size_t *psize) +{ + struct state *st; + FILE *fp; + + if (pbuf == NULL || psize == NULL) { + errno = EINVAL; + return (NULL); + } + + if ((st = malloc(sizeof(*st))) == NULL) + return (NULL); + + if ((fp = __sfp()) == NULL) { + free(st); + return (NULL); + } + + st->size = BUFSIZ * sizeof(wchar_t); + if ((st->string = calloc(1, st->size)) == NULL) { + free(st); + fp->_flags = 0; + return (NULL); + } + + *st->string = L'\0'; + st->pos = 0; + st->len = 0; + st->pbuf = pbuf; + st->psize = psize; + bzero(&st->mbs, sizeof(st->mbs)); + + *pbuf = st->string; + *psize = st->len; + + fp->_flags = __SWR; + fp->_file = -1; + fp->_cookie = st; + fp->_read = NULL; + fp->_write = wmemstream_write; + fp->_seek = wmemstream_seek; + fp->_close = wmemstream_close; + _SET_ORIENTATION(fp, 1); + + return (fp); +} |