libc -- Initial fmemopen support.
authorVenkatesh Srinivas <me@endeavour.zapto.org>
Wed, 11 May 2011 17:31:35 +0000 (10:31 -0700)
committerVenkatesh Srinivas <me@endeavour.zapto.org>
Wed, 11 May 2011 17:31:35 +0000 (10:31 -0700)
fmemopen allows wrapping a memory buffer in the FILE* interface.

fmemopen was added to POSIX 200809. This version is based around a patch
from Hiten Pandya for FreeBSD. This version does not currently support all of
POSIX's mode strings.

include/stdio.h
lib/libc/stdio/Makefile.inc
lib/libc/stdio/fmemopen.c [new file with mode: 0644]

index 2f241ad..fd29bb9 100644 (file)
@@ -299,6 +299,7 @@ ssize_t      getdelim(char ** __restrict, size_t * __restrict, int,
                  FILE * __restrict);
 int     renameat(int, const char *, int, const char *);
 int     vdprintf(int, const char * __restrict, __va_list);
+FILE   *fmemopen(void *__restrict, size_t, const char *__restrict);
 
 /*
  * Every programmer and his dog wrote functions called getline() and dprintf()
index 376574a..44e1421 100644 (file)
@@ -9,7 +9,8 @@ SRCS+=  __fpending.c _flock_stub.c \
        asprintf.c clrerr.c dprintf.c \
        fclose.c fcloseall.c fcookie.c fdopen.c feof.c ferror.c \
        fflush.c fgetc.c fgetln.c fgetpos.c fgets.c fgetwc.c fgetwln.c \
-       fgetws.c fileno.c findfp.c flags.c fopen.c fprintf.c fpurge.c \
+       fgetws.c fileno.c findfp.c flags.c fmemopen.c \
+       fopen.c fprintf.c fpurge.c \
        fputc.c fputs.c fputwc.c fputws.c fread.c freopen.c fscanf.c \
        fseek.c fsetpos.c ftell.c funopen.c fvwrite.c fwalk.c fwide.c \
        fwprintf.c fwrite.c fwscanf.c getc.c getchar.c \
diff --git a/lib/libc/stdio/fmemopen.c b/lib/libc/stdio/fmemopen.c
new file mode 100644 (file)
index 0000000..eceec3a
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2011 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Venkatesh Srinivas <me@endeavour.zapto.org>.
+ *
+ * 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.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ */
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <hiten@uk.FreeBSD.ORG> wrote this file.  As long as you retain this notice
+ * you can do whatever you want with this stuff. If we meet some day, and you
+ * think this stuff is worth it, you can buy me a beer in return. Hiten Pandya. 
+ * ----------------------------------------------------------------------------
+ *
+ * $FreeBSD: src/sys/dev/md/md.c,v 1.8.2.2 2002/08/19 17:43:34 jdp Exp $
+ */
+
+/*
+ * fmemopen -- Open a memory buffer stream
+ *
+ * POSIX 1003.1-2008
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+
+static int __fmemopen_closefn (void *);
+static int __fmemopen_readfn(void *, char *, int);
+static fpos_t __fmemopen_seekfn (void *, fpos_t, int);
+static int __fmemopen_writefn(void *, const char *, int);
+
+FILE *fmemopen (void *, size_t, const char *);
+
+struct fmemopen_cookie {
+       char *buffer;
+       int mybuffer;
+       size_t size;
+       size_t pos;
+       size_t maxpos;
+};
+
+static int __fmemopen_readfn(void *cookie, char *buf, int len)
+{
+       struct fmemopen_cookie *c;
+       c = (struct fmemopen_cookie *) cookie;
+       
+       if (c == NULL) {
+               errno = EBADF;
+               return (-1);
+       }
+       
+       if ((c->pos + len) > c->size) {
+               if (c->pos == c->size) 
+                       return -1;
+               len = c->size - c->pos;
+       }
+       
+       memcpy(buf, &(c->buffer[c->pos]), len);
+       
+       c->pos += len;
+       
+       if (c->pos > c->maxpos) 
+               c->maxpos = c->pos;
+       
+       return (len);
+}
+
+static int __fmemopen_writefn (void *cookie, const char *buf, int len)
+{
+       struct fmemopen_cookie *c;
+       int addnullc;
+       
+       c = (struct fmemopen_cookie *) cookie;
+       if (c == NULL) {
+               errno = EBADF;
+               return (-1);
+       }
+       
+       addnullc = ((len == 0) || (buf[len - 1] != '\0') ) ? 1 : 0;
+       
+       if ((c->pos + len + addnullc) > c->size) {
+               if ((c->pos + addnullc) == c->size) 
+                       return -1;
+               len = c->size - c->pos - addnullc;
+       }
+       
+       memcpy(&(c->buffer[c->pos]), buf, len);
+       
+       c->pos += len;
+       if (c->pos > c->maxpos) {
+               c->maxpos = c->pos;
+               if (addnullc) 
+                       c->buffer[c->maxpos] = '\0';
+       }
+       
+       return (len);
+}
+
+static fpos_t __fmemopen_seekfn(void *cookie, fpos_t pos, int whence)
+{
+       fpos_t np = 0;
+       struct fmemopen_cookie *c;
+       
+       c = (struct fmemopen_cookie *) cookie;
+       
+       switch(whence) {
+       case (SEEK_SET): 
+               np = pos; 
+               break;
+       case (SEEK_CUR): 
+               np = c->pos + pos; 
+               break;
+       case (SEEK_END): 
+               np = c->size - pos; 
+               break;
+       }
+       
+       if ((np < 0) || (np > c->size)) 
+               return (-1);
+       
+       c->pos = np;
+       
+       return (np);
+}
+
+static int __fmemopen_closefn (void *cookie)
+{
+       struct fmemopen_cookie *c;
+       c = (struct fmemopen_cookie*) cookie;
+       
+       if (c->mybuffer) 
+               free(c->buffer);
+       free(c);
+       
+       return (0);
+}
+
+FILE *fmemopen(void *restrict buffer, size_t s, const char *restrict mode)
+{
+       FILE *f = NULL;
+       struct fmemopen_cookie *c;
+       c = malloc(sizeof (struct fmemopen_cookie));
+       
+       if (c == NULL)
+               return NULL;
+       
+       c->mybuffer = (buffer == NULL);
+       
+       if (c->mybuffer) {
+               c->buffer = malloc(s);
+               if (c->buffer == NULL) {
+                       free(c);
+                       return NULL;
+               }
+               c->buffer[0] = '\0';
+       } else {
+               c->buffer = buffer;
+       }
+       c->size = s;
+       if (mode[0] == 'w')
+               c->buffer[0] = '\0';
+       c->maxpos = strlen(c->buffer);
+       
+       if (mode[0] == 'a')
+               c->pos = c->maxpos;
+       else
+               c->pos = 0;
+       
+       f = funopen(c,
+                   __fmemopen_readfn, /* string stream read */
+                   __fmemopen_writefn, /* string stream write */
+                   __fmemopen_seekfn, /* string stream seek */
+                   __fmemopen_closefn /* string stream close */
+                   );
+       
+       if (f == NULL)
+               free(c);
+       
+       return (f);
+}