Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F172038062
D57461.id179249.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
D57461.id179249.diff
View Options
diff --git a/lib/libc/stdio/Makefile.inc b/lib/libc/stdio/Makefile.inc
--- a/lib/libc/stdio/Makefile.inc
+++ b/lib/libc/stdio/Makefile.inc
@@ -12,7 +12,7 @@
ftell.c funopen.c fvwrite.c fwalk.c fwide.c fwprintf.c fwscanf.c \
fwrite.c getc.c getchar.c getdelim.c getline.c \
gets.c gets_s.c getw.c getwc.c getwchar.c makebuf.c mktemp.c \
- open_memstream.c open_wmemstream.c \
+ open_memstream.c \
perror.c printf.c printf-pos.c putc.c putchar.c \
puts.c putw.c putwc.c putwchar.c \
refill.c remove.c rewind.c rget.c scanf.c setbuf.c setbuffer.c \
diff --git a/lib/libc/stdio/open_memstream.c b/lib/libc/stdio/open_memstream.c
--- a/lib/libc/stdio/open_memstream.c
+++ b/lib/libc/stdio/open_memstream.c
@@ -46,22 +46,63 @@
/* XXX: There is no FPOS_MAX. This assumes fpos_t is an off_t. */
#define FPOS_MAX OFF_MAX
+struct memstream;
+typedef size_t (buflen_fn)(struct memstream *, const char *, int);
+typedef ssize_t (bufcopy_fn)(struct memstream *, const char *, int);
+typedef void (bufseek_fn)(struct memstream *, fpos_t, fpos_t);
+
+static bufcopy_fn bufcopy;
+
+static bufcopy_fn wbufcopy;
+static buflen_fn wbuflen;
+static bufseek_fn wbufseek;
+
+struct streamcfg {
+ bufcopy_fn *cfg_bufcopy;
+ buflen_fn *cfg_buflen;
+ bufseek_fn *cfg_bufseek;
+ size_t cfg_ctx_size;
+ size_t cfg_elem_size;
+};
+
struct memstream {
- char **bufp;
+ const struct streamcfg *cfg;
+ void **bufp;
size_t *sizep;
size_t size;
ssize_t len;
fpos_t offset;
};
+struct wmemstream {
+ struct memstream stream;
+ mbstate_t mbstate;
+};
+
+static const struct streamcfg memstream_cfg = {
+ .cfg_bufcopy = &bufcopy,
+ .cfg_ctx_size = sizeof(struct memstream),
+ .cfg_elem_size = 1,
+};
+
+static const struct streamcfg wmemstream_cfg = {
+ .cfg_bufcopy = &wbufcopy,
+ .cfg_buflen = &wbuflen,
+ .cfg_bufseek = &wbufseek,
+ .cfg_ctx_size = sizeof(struct wmemstream),
+ .cfg_elem_size = sizeof(wchar_t),
+};
+
static int
memstream_grow(struct memstream *ms, fpos_t newoff)
{
- char *buf;
+ const struct streamcfg *cfg = ms->cfg;
+ uint8_t *buf;
ssize_t newsize;
+ size_t elem_size = cfg->cfg_elem_size;
- if (newoff < 0 || newoff >= SSIZE_MAX)
- newsize = SSIZE_MAX - 1;
+ if (newoff < 0 || newoff >= SSIZE_MAX / elem_size)
+ newsize = SSIZE_MAX / elem_size - 1;
else
newsize = newoff;
if (newsize > ms->size) {
@@ -73,15 +114,15 @@
/* Leave newsize untouched for the later ms->len update. */
growsize = MAX(growsize, newsize);
- buf = realloc(*ms->bufp, growsize + 1);
+ buf = reallocarray(*ms->bufp, growsize + 1, elem_size);
if (buf == NULL)
return (0);
-
#ifdef DEBUG
fprintf(stderr, "MS: %p growing from %zd to %zd\n",
ms, ms->size, newsize);
#endif
- memset(buf + ms->size + 1, 0, growsize - ms->size);
+ memset(buf + (ms->size + 1) * elem_size, 0,
+ (growsize - ms->size) * elem_size);
*ms->bufp = buf;
ms->size = growsize;
}
@@ -99,39 +140,144 @@
*ms->sizep = ms->len < ms->offset ? ms->len : ms->offset;
}
+/*
+ * Based on a starting multibyte state and an input buffer, determine
+ * how many wchar_t's would be output. This doesn't use mbsnrtowcs()
+ * so that it can handle embedded null characters.
+ */
+static size_t
+wbuflen(struct memstream *stream, const char *buf, int len)
+{
+ struct wmemstream *wstream;
+ mbstate_t lenstate;
+ size_t charlen, count;
+
+ count = 0;
+ wstream = __containerof(stream, struct wmemstream, stream);
+ lenstate = wstream->mbstate;
+ while (len > 0) {
+ charlen = mbrlen(buf, len, &lenstate);
+ if (charlen == (size_t)-1)
+ return (-1);
+ if (charlen == (size_t)-2)
+ break;
+ if (charlen == 0)
+ /* XXX: Not sure how else to handle this. */
+ charlen = 1;
+ len -= charlen;
+ buf += charlen;
+ count++;
+ }
+ return (count);
+}
+
+static ssize_t
+bufcopy(struct memstream *ms, const char *buf, int len)
+{
+ ssize_t tocopy;
+
+ assert(ms->offset + len <= ms->len);
+
+ tocopy = MIN(len, ms->len - ms->offset);
+ memcpy(*ms->bufp + ms->offset, buf, tocopy);
+ ms->offset += tocopy;
+ return (tocopy);
+}
+
+static ssize_t
+wbufcopy(struct memstream *ms, const char *buf, int len)
+{
+ struct wmemstream *wstream;
+ size_t charlen;
+ ssize_t consumed;
+
+ wstream = __containerof(ms, struct wmemstream, stream);
+
+ /*
+ * This copies characters one at a time rather than using
+ * mbsnrtowcs() so it can properly handle embedded null
+ * characters.
+ */
+ consumed = 0;
+ while (len > 0 && ms->offset < ms->len) {
+ charlen = mbrtowc(*ms->bufp + ms->offset, buf, len,
+ &wstream->mbstate);
+ if (charlen == (size_t)-1) {
+ if (consumed == 0) {
+ errno = EILSEQ;
+ return (-1);
+ }
+ /* Treat it as a successful short write. */
+ break;
+ }
+ if (charlen == 0)
+ /* XXX: Not sure how else to handle this. */
+ charlen = 1;
+ if (charlen == (size_t)-2) {
+ consumed += len;
+ len = 0;
+ } else {
+ consumed += charlen;
+ buf += charlen;
+ len -= charlen;
+ ms->offset++;
+ }
+ }
+
+ return (consumed);
+}
+
static int
memstream_write(void *cookie, const char *buf, int len)
{
+ const struct streamcfg *cfg;
struct memstream *ms;
- ssize_t tocopy;
+ ssize_t buflen, consumed;
ms = cookie;
- if (!memstream_grow(ms, ms->offset + len))
+ cfg = ms->cfg;
+ if (cfg->cfg_buflen != NULL)
+ buflen = cfg->cfg_buflen(ms, buf, len);
+ else
+ buflen = len;
+ if (buflen < 0) {
+ errno = EILSEQ;
return (-1);
- tocopy = ms->len - ms->offset;
- if (len < tocopy)
- tocopy = len;
- memcpy(*ms->bufp + ms->offset, buf, tocopy);
- ms->offset += tocopy;
+ }
+ if (!memstream_grow(ms, ms->offset + buflen))
+ return (-1);
+
+ consumed = cfg->cfg_bufcopy(ms, buf, len);
+ if (consumed < 0)
+ return (-1);
+
memstream_update(ms);
#ifdef DEBUG
- fprintf(stderr, "MS: write(%p, %d) = %zd\n", ms, len, tocopy);
+ fprintf(stderr, "MS: write(%p, %d) = %zd\n", ms, len, consumed);
#endif
- return (tocopy);
+ return (consumed);
+}
+
+static void
+wbufseek(struct memstream *ms, fpos_t oldpos, fpos_t newpos)
+{
+ struct wmemstream *wstream;
+
+ wstream = __containerof(ms, struct wmemstream, stream);
+ /* Position changed: reset the multibyte state. */
+ memset(&wstream->mbstate, 0, sizeof(wstream->mbstate));
}
static fpos_t
memstream_seek(void *cookie, fpos_t pos, int whence)
{
+ const struct streamcfg *cfg;
struct memstream *ms;
-#ifdef DEBUG
fpos_t old;
-#endif
ms = cookie;
-#ifdef DEBUG
+ cfg = ms->cfg;
old = ms->offset;
-#endif
switch (whence) {
case SEEK_SET:
/* _fseeko() checks for negative offsets. */
@@ -167,10 +313,14 @@
ms->offset = ms->len + pos;
break;
}
+
+ /* Specific stream may need to update its own state. */
+ if (old != pos && cfg->cfg_bufseek != NULL)
+ cfg->cfg_bufseek(ms, old, pos);
memstream_update(ms);
#ifdef DEBUG
- fprintf(stderr, "MS: seek(%p, %jd, %d) %jd -> %jd\n", ms, (intmax_t)pos,
- whence, (intmax_t)old, (intmax_t)ms->offset);
+ fprintf(stderr, "MS: seek(%p, %jd, %d) %jd -> %jd\n", ms,
+ (intmax_t)pos, whence, (intmax_t)old, (intmax_t)ms->offset);
#endif
return (ms->offset);
}
@@ -183,9 +333,10 @@
return (0);
}
-FILE *
-open_memstream(char **bufp, size_t *sizep)
+static FILE *
+open_memstream_cfg(const struct streamcfg *cfg, void **bufp, size_t *sizep)
{
+ void *ctx;
struct memstream *ms;
int save_errno;
FILE *fp;
@@ -194,33 +345,60 @@
errno = EINVAL;
return (NULL);
}
- *bufp = calloc(1, 1);
+
+ *bufp = calloc(1, cfg->cfg_elem_size);
if (*bufp == NULL)
return (NULL);
- ms = malloc(sizeof(*ms));
- if (ms == NULL) {
+
+ /*
+ * Trip through `ctx` is not strictly necessary, but trying to maintain
+ * some discipline: we're allocating a block of context and it's
+ * expected to embed a struct memstream.
+ */
+ assert(cfg->cfg_ctx_size >= sizeof(*ms));
+ ctx = calloc(1, cfg->cfg_ctx_size);
+ if (ctx == NULL) {
save_errno = errno;
free(*bufp);
*bufp = NULL;
errno = save_errno;
return (NULL);
}
+
+ ms = ctx;
+ ms->cfg = cfg;
ms->bufp = bufp;
ms->sizep = sizep;
- ms->size = 0;
- ms->len = 0;
- ms->offset = 0;
+
memstream_update(ms);
- fp = funopen(ms, NULL, memstream_write, memstream_seek,
+ fp = funopen(ctx, NULL, memstream_write, memstream_seek,
memstream_close);
if (fp == NULL) {
save_errno = errno;
- free(ms);
+ free(ctx);
free(*bufp);
*bufp = NULL;
errno = save_errno;
return (NULL);
}
- fwide(fp, -1);
+
+ return (fp);
+}
+
+FILE *
+open_memstream(char **bufp, size_t *sizep)
+{
+ return (open_memstream_cfg(&memstream_cfg, (void **)bufp, sizep));
+}
+
+FILE *
+open_wmemstream(wchar_t **bufp, size_t *sizep)
+{
+ FILE *fp;
+
+ fp = open_memstream_cfg(&wmemstream_cfg, (void **)bufp, sizep);
+ if (fp != NULL)
+ fwide(fp, 1);
+
return (fp);
}
diff --git a/lib/libc/stdio/open_wmemstream.c b/lib/libc/stdio/open_wmemstream.c
deleted file mode 100644
--- a/lib/libc/stdio/open_wmemstream.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2013 Hudson River Trading LLC
- * Written by: John H. Baldwin <jhb@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "namespace.h"
-#include <sys/param.h>
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdbool.h>
-#include <stdckdint.h>
-#ifdef DEBUG
-#include <stdint.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wchar.h>
-#include "un-namespace.h"
-
-/* XXX: There is no FPOS_MAX. This assumes fpos_t is an off_t. */
-#define FPOS_MAX OFF_MAX
-
-struct wmemstream {
- wchar_t **bufp;
- size_t *sizep;
- size_t size;
- ssize_t len;
- fpos_t offset;
- mbstate_t mbstate;
-};
-
-static int
-wmemstream_grow(struct wmemstream *ms, fpos_t newoff)
-{
- wchar_t *buf;
- ssize_t newsize;
-
- if (newoff < 0 || newoff >= SSIZE_MAX / sizeof(wchar_t))
- newsize = SSIZE_MAX / sizeof(wchar_t) - 1;
- else
- newsize = newoff;
- if (newsize > ms->size) {
- size_t growsize;
-
- if (ckd_add(&growsize, ms->size, ms->size / 2))
- growsize = SSIZE_MAX - 1;
-
- /* Leave newsize untouched for the later ms->len update. */
- growsize = MAX(growsize, newsize);
-
- buf = reallocarray(*ms->bufp, growsize + 1, sizeof(wchar_t));
- if (buf == NULL)
- return (0);
-#ifdef DEBUG
- fprintf(stderr, "WMS: %p growing from %zd to %zd\n",
- ms, ms->size, newsize);
-#endif
- wmemset(buf + ms->size + 1, 0, growsize - ms->size);
- *ms->bufp = buf;
- ms->size = growsize;
- }
-
- if (newsize > ms->len)
- ms->len = newsize;
- return (1);
-}
-
-static void
-wmemstream_update(struct wmemstream *ms)
-{
-
- assert(ms->len >= 0 && ms->offset >= 0);
- *ms->sizep = ms->len < ms->offset ? ms->len : ms->offset;
-}
-
-/*
- * Based on a starting multibyte state and an input buffer, determine
- * how many wchar_t's would be output. This doesn't use mbsnrtowcs()
- * so that it can handle embedded null characters.
- */
-static size_t
-wbuflen(const mbstate_t *state, const char *buf, int len)
-{
- mbstate_t lenstate;
- size_t charlen, count;
-
- count = 0;
- lenstate = *state;
- while (len > 0) {
- charlen = mbrlen(buf, len, &lenstate);
- if (charlen == (size_t)-1)
- return (-1);
- if (charlen == (size_t)-2)
- break;
- if (charlen == 0)
- /* XXX: Not sure how else to handle this. */
- charlen = 1;
- len -= charlen;
- buf += charlen;
- count++;
- }
- return (count);
-}
-
-static int
-wmemstream_write(void *cookie, const char *buf, int len)
-{
- struct wmemstream *ms;
- ssize_t consumed, wlen;
- size_t charlen;
-
- ms = cookie;
- wlen = wbuflen(&ms->mbstate, buf, len);
- if (wlen < 0) {
- errno = EILSEQ;
- return (-1);
- }
- if (!wmemstream_grow(ms, ms->offset + wlen))
- return (-1);
-
- /*
- * This copies characters one at a time rather than using
- * mbsnrtowcs() so it can properly handle embedded null
- * characters.
- */
- consumed = 0;
- while (len > 0 && ms->offset < ms->len) {
- charlen = mbrtowc(*ms->bufp + ms->offset, buf, len,
- &ms->mbstate);
- if (charlen == (size_t)-1) {
- if (consumed == 0) {
- errno = EILSEQ;
- return (-1);
- }
- /* Treat it as a successful short write. */
- break;
- }
- if (charlen == 0)
- /* XXX: Not sure how else to handle this. */
- charlen = 1;
- if (charlen == (size_t)-2) {
- consumed += len;
- len = 0;
- } else {
- consumed += charlen;
- buf += charlen;
- len -= charlen;
- ms->offset++;
- }
- }
- wmemstream_update(ms);
-#ifdef DEBUG
- fprintf(stderr, "WMS: write(%p, %d) = %zd\n", ms, len, consumed);
-#endif
- return (consumed);
-}
-
-static fpos_t
-wmemstream_seek(void *cookie, fpos_t pos, int whence)
-{
- struct wmemstream *ms;
- fpos_t old;
-
- ms = cookie;
- old = ms->offset;
- switch (whence) {
- case SEEK_SET:
- /* _fseeko() checks for negative offsets. */
- assert(pos >= 0);
- ms->offset = pos;
- break;
- case SEEK_CUR:
- /* This is only called by _ftello(). */
- assert(pos == 0);
- break;
- case SEEK_END:
- if (pos < 0) {
- if (pos + ms->len < 0) {
-#ifdef DEBUG
- fprintf(stderr,
- "WMS: bad SEEK_END: pos %jd, len %zd\n",
- (intmax_t)pos, ms->len);
-#endif
- errno = EINVAL;
- return (-1);
- }
- } else {
- if (FPOS_MAX - ms->len < pos) {
-#ifdef DEBUG
- fprintf(stderr,
- "WMS: bad SEEK_END: pos %jd, len %zd\n",
- (intmax_t)pos, ms->len);
-#endif
- errno = EOVERFLOW;
- return (-1);
- }
- }
- ms->offset = ms->len + pos;
- break;
- }
- /* Reset the multibyte state if a seek changes the position. */
- if (ms->offset != old)
- memset(&ms->mbstate, 0, sizeof(ms->mbstate));
- wmemstream_update(ms);
-#ifdef DEBUG
- fprintf(stderr, "WMS: seek(%p, %jd, %d) %jd -> %jd\n", ms,
- (intmax_t)pos, whence, (intmax_t)old, (intmax_t)ms->offset);
-#endif
- return (ms->offset);
-}
-
-static int
-wmemstream_close(void *cookie)
-{
-
- free(cookie);
- return (0);
-}
-
-FILE *
-open_wmemstream(wchar_t **bufp, size_t *sizep)
-{
- struct wmemstream *ms;
- int save_errno;
- FILE *fp;
-
- if (bufp == NULL || sizep == NULL) {
- errno = EINVAL;
- return (NULL);
- }
- *bufp = calloc(1, sizeof(wchar_t));
- if (*bufp == NULL)
- return (NULL);
- ms = malloc(sizeof(*ms));
- if (ms == NULL) {
- save_errno = errno;
- free(*bufp);
- *bufp = NULL;
- errno = save_errno;
- return (NULL);
- }
- ms->bufp = bufp;
- ms->sizep = sizep;
- ms->size = 0;
- ms->len = 0;
- ms->offset = 0;
- memset(&ms->mbstate, 0, sizeof(mbstate_t));
- wmemstream_update(ms);
- fp = funopen(ms, NULL, wmemstream_write, wmemstream_seek,
- wmemstream_close);
- if (fp == NULL) {
- save_errno = errno;
- free(ms);
- free(*bufp);
- *bufp = NULL;
- errno = save_errno;
- return (NULL);
- }
- fwide(fp, 1);
- return (fp);
-}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Sep 16, 3:17 PM (6 h, 19 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
39019149
Default Alt Text
D57461.id179249.diff (15 KB)
Attached To
Mode
D57461: (RFC) stdio: consolidate the two memstream implementations
Attached
Detach File
Event Timeline
Log In to Comment