aboutsummaryrefslogtreecommitdiff
path: root/src/common/fmemopen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/fmemopen.c')
-rw-r--r--src/common/fmemopen.c225
1 files changed, 225 insertions, 0 deletions
diff --git a/src/common/fmemopen.c b/src/common/fmemopen.c
new file mode 100644
index 0000000..d42fc30
--- /dev/null
+++ b/src/common/fmemopen.c
@@ -0,0 +1,225 @@
+/*
+ This file was retrieved from
+ http://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/lib/libc/stdio/fmemopen.c
+ on 26/04/2013 by Abel Luck for inclusion in tlsdate for the Android port.
+*/
+#include "android.h"
+/* $NetBSD: fmemopen.c,v 1.4 2010/09/27 16:50:13 tnozaki Exp $ */
+
+/*-
+ * Copyright (c)2007, 2010 Takehiko NOZAKI,
+ * Copyright (c) 2012, Venkatesh Srinivas <vsrinivas@dragonflybsd.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 <sys/param.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+//#include "local.h"
+//#include "priv_stdio.h"
+
+struct fmemopen_cookie {
+ char *head, *tail, *cur, *eob;
+};
+
+static int
+fmemopen_read(void *cookie, char *buf, int nbytes)
+{
+ struct fmemopen_cookie *p;
+ char *s;
+ int len;
+
+ assert(cookie != NULL);
+ assert(buf != NULL && nbytes > 0);
+
+ p = cookie;
+ s = p->cur;
+ len = MIN(p->tail - p->cur, nbytes);
+ bcopy(p->cur, buf, len);
+ p->cur += len;
+
+ return (int)(p->cur - s);
+}
+
+static int
+fmemopen_write(void *cookie, const char *buf, int nbytes)
+{
+ struct fmemopen_cookie *p;
+ char *s;
+ int len;
+
+ assert(cookie != NULL);
+ assert(buf != NULL && nbytes > 0);
+
+ p = cookie;
+ if (p->cur >= p->tail)
+ return 0;
+ s = p->cur;
+
+ len = MIN(p->tail - p->cur, nbytes);
+
+ bcopy(buf, p->cur, len);
+
+ p->cur += len - 1;
+ if (p->cur == p->tail - 1) {
+ *p->cur = '\0';
+ if (buf[len - 1] == '\0')
+ p->cur++;
+ } else {
+ *++p->cur = '\0';
+ }
+
+ if (p->cur > p->eob)
+ p->eob = p->cur;
+
+ return (int)(p->cur - s);
+}
+
+static fpos_t
+fmemopen_seek(void *cookie, fpos_t offset, int whence)
+{
+ struct fmemopen_cookie *p;
+
+ assert(cookie != NULL);
+
+ p = (struct fmemopen_cookie *)cookie;
+ switch (whence) {
+ case SEEK_SET:
+ break;
+ case SEEK_CUR:
+ offset += p->cur - p->head;
+ break;
+ case SEEK_END:
+ offset += p->eob - p->head;
+ break;
+ default:
+ errno = EINVAL;
+ goto error;
+ }
+ if (offset >= (fpos_t)0 && offset <= p->tail - p->head) {
+ p->cur = p->head + (ptrdiff_t)offset;
+ return (fpos_t)(p->cur - p->head);
+ }
+error:
+ return (fpos_t)-1;
+}
+
+static int
+fmemopen_close0(void *cookie)
+{
+ assert(cookie != NULL);
+
+ free(cookie);
+
+ return 0;
+}
+
+static int
+fmemopen_close1(void *cookie)
+{
+ struct fmemopen_cookie *p;
+
+ assert(cookie != NULL);
+
+ p = cookie;
+ free(p->head);
+ free(p);
+
+ return 0;
+}
+
+
+FILE *
+fmemopen(void * __restrict buf, size_t size, const char * __restrict mode)
+{
+ int flags, oflags;
+ FILE *fp;
+ struct fmemopen_cookie *cookie;
+
+ if (size < (size_t)1)
+ goto invalid;
+
+ flags = __sflags(mode, &oflags);
+ if (flags == 0)
+ return NULL;
+
+ if ((oflags & O_RDWR) == 0 && buf == NULL)
+ goto invalid;
+
+ fp = __sfp();
+ if (fp == NULL)
+ return NULL;
+
+ cookie = malloc(sizeof(*cookie));
+ if (cookie == NULL)
+ goto release;
+
+ if (buf == NULL) {
+ cookie->head = malloc(size);
+ if (cookie->head == NULL) {
+ free(cookie);
+ goto release;
+ }
+ *cookie->head = '\0';
+ fp->_close = &fmemopen_close1;
+ } else {
+ cookie->head = (char *)buf;
+ if (oflags & O_TRUNC)
+ *cookie->head = '\0';
+ fp->_close = &fmemopen_close0;
+ }
+
+ cookie->tail = cookie->head + size;
+ cookie->eob = cookie->head;
+ do {
+ if (*cookie->eob == '\0')
+ break;
+ ++cookie->eob;
+ } while (--size > 0);
+
+ cookie->cur = (oflags & O_APPEND) ? cookie->eob : cookie->head;
+
+ // fp->pub._flags = flags;
+ fp->_write = (flags & __SRD) ? NULL : &fmemopen_write;
+ fp->_read = (flags & __SWR) ? NULL : &fmemopen_read;
+ fp->_seek = &fmemopen_seek;
+ fp->_cookie = (void *)cookie;
+
+ return fp;
+
+invalid:
+ errno = EINVAL;
+ return NULL;
+
+release:
+ //fp->pub._flags = 0;
+ return NULL;
+}
+
+