Page MenuHomeFreeBSD

D57461.id179249.diff
No OneTemporary

D57461.id179249.diff

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

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)

Event Timeline