mailing list of musl libc
 help / color / mirror / code / Atom feed
* [PATCH] stdio: implement fopencookie(3)
@ 2017-10-05  6:48 William Pitcock
  2017-10-05 10:10 ` Szabolcs Nagy
  0 siblings, 1 reply; 11+ messages in thread
From: William Pitcock @ 2017-10-05  6:48 UTC (permalink / raw)
  To: musl; +Cc: William Pitcock

---
 include/stdio.h         |  9 +++++
 src/stdio/fopencookie.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+)
 create mode 100644 src/stdio/fopencookie.c

diff --git a/include/stdio.h b/include/stdio.h
index 884d2e6a..998883e5 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -182,6 +182,15 @@ int vasprintf(char **, const char *, __isoc_va_list);
 #ifdef _GNU_SOURCE
 char *fgets_unlocked(char *, int, FILE *);
 int fputs_unlocked(const char *, FILE *);
+
+typedef struct {
+	ssize_t (*read)(void *cookie, char *buf, size_t size);
+	ssize_t (*write)(void *cookie, const char *buf, size_t size);
+	int (*seek)(void *cookie, off_t *offset, int whence);
+	int (*close)(void *cookie);
+} cookie_io_functions_t;
+
+FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t io_funcs);
 #endif
 
 #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
diff --git a/src/stdio/fopencookie.c b/src/stdio/fopencookie.c
new file mode 100644
index 00000000..e0b5a119
--- /dev/null
+++ b/src/stdio/fopencookie.c
@@ -0,0 +1,98 @@
+#define _GNU_SOURCE
+#include "stdio_impl.h"
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+struct fcookie {
+	void *cookie;
+	cookie_io_functions_t iofuncs;
+};
+
+static size_t cookieread(FILE *f, unsigned char *buf, size_t len)
+{
+	struct fcookie *fc = f->cookie;
+	size_t ret;
+	if (fc->iofuncs.read == NULL) return -1;
+	ret = fc->iofuncs.read(fc->cookie, (char *) buf, len);
+	if (ret == 0) f->flags |= F_EOF;
+	f->rpos = f->buf;
+	f->rend = f->buf + ret;
+	return ret;
+}
+
+static size_t cookiewrite(FILE *f, const unsigned char *buf, size_t len)
+{
+	struct fcookie *fc = f->cookie;
+	size_t ret;
+	size_t len2 = f->wpos - f->wbase;
+	if (fc->iofuncs.write == NULL) return -1;
+	if (len2) {
+		f->wpos = f->wbase;
+		if (cookiewrite(f, f->wpos, len2) < len2) return 0;
+	}
+	return fc->iofuncs.write(fc->cookie, (const char *) buf, len);
+}
+
+static off_t cookieseek(FILE *f, off_t off, int whence)
+{
+	struct fcookie *fc = f->cookie;
+	if (fc->iofuncs.seek) return fc->iofuncs.seek(fc->cookie, &off, whence);
+	return -1;
+}
+
+static int cookieclose(FILE *f)
+{
+	struct fcookie *fc = f->cookie;
+	if (fc->iofuncs.close) return fc->iofuncs.close(fc->cookie);
+	return 0;
+}
+
+FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t iofuncs)
+{
+	FILE *f;
+	struct winsize wsz;
+	struct fcookie *fc;
+
+	/* Check for valid initial mode character */
+	if (!strchr("rwa", *mode)) {
+		errno = EINVAL;
+		return 0;
+	}
+
+	/* Allocate FILE+fcookie+buffer or fail */
+	if (!(f=malloc(sizeof *f + sizeof *fc + UNGET + BUFSIZ))) return 0;
+
+	/* Zero-fill only the struct, not the buffer */
+	memset(f, 0, sizeof *f);
+
+	/* Impose mode restrictions */
+	if (!strchr(mode, '+')) f->flags = (*mode == 'r') ? F_NOWR : F_NORD;
+
+	/* Set up our fcookie */
+	fc = (void *)(f + 1);
+	fc->cookie = cookie;
+	fc->iofuncs.read = iofuncs.read;
+	fc->iofuncs.write = iofuncs.write;
+	fc->iofuncs.seek = iofuncs.seek;
+	fc->iofuncs.close = iofuncs.close;
+
+	f->fd = -1;
+	f->cookie = fc;
+	f->buf = (unsigned char *)f + sizeof *f + sizeof *fc + UNGET;
+	f->buf_size = BUFSIZ;
+	f->lbf = EOF;
+
+	/* Initialize op ptrs. No problem if some are unneeded. */
+	f->read = cookieread;
+	f->write = cookiewrite;
+	f->seek = cookieseek;
+	f->close = cookieclose;
+
+	if (!libc.threaded) f->lock = -1;
+
+	/* Add new FILE to open file list */
+	return __ofl_add(f);
+}
-- 
2.13.3



^ permalink raw reply	[flat|nested] 11+ messages in thread
* [PATCH] stdio: implement fopencookie(3)
@ 2017-10-10 18:03 William Pitcock
  2017-10-10 18:51 ` Jens Gustedt
  0 siblings, 1 reply; 11+ messages in thread
From: William Pitcock @ 2017-10-10 18:03 UTC (permalink / raw)
  To: musl; +Cc: William Pitcock

The fopencookie(3) function allows the programmer to create a custom
stdio implementation, using four hook functions which operate on a
"cookie" data type.

Changelog:

v3:
- remove spurious `struct winsize`
- make f->lock unconditionally 0

v2:
- properly implement stdio buffering

v1:
- initial proof of concept
---
 include/stdio.h         |  9 +++++
 src/stdio/fopencookie.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)
 create mode 100644 src/stdio/fopencookie.c

diff --git a/include/stdio.h b/include/stdio.h
index 884d2e6a..998883e5 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -182,6 +182,15 @@ int vasprintf(char **, const char *, __isoc_va_list);
 #ifdef _GNU_SOURCE
 char *fgets_unlocked(char *, int, FILE *);
 int fputs_unlocked(const char *, FILE *);
+
+typedef struct {
+	ssize_t (*read)(void *cookie, char *buf, size_t size);
+	ssize_t (*write)(void *cookie, const char *buf, size_t size);
+	int (*seek)(void *cookie, off_t *offset, int whence);
+	int (*close)(void *cookie);
+} cookie_io_functions_t;
+
+FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t io_funcs);
 #endif
 
 #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
diff --git a/src/stdio/fopencookie.c b/src/stdio/fopencookie.c
new file mode 100644
index 00000000..baad2585
--- /dev/null
+++ b/src/stdio/fopencookie.c
@@ -0,0 +1,96 @@
+#define _GNU_SOURCE
+#include "stdio_impl.h"
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+struct fcookie {
+	void *cookie;
+	cookie_io_functions_t iofuncs;
+};
+
+static size_t cookieread(FILE *f, unsigned char *buf, size_t len)
+{
+	struct fcookie *fc = f->cookie;
+	size_t ret;
+	if (fc->iofuncs.read == NULL) return -1;
+	ret = fc->iofuncs.read(fc->cookie, (char *) buf, len);
+	if (ret == 0) f->flags |= F_EOF;
+	f->rpos = f->buf;
+	f->rend = f->buf + ret;
+	return ret;
+}
+
+static size_t cookiewrite(FILE *f, const unsigned char *buf, size_t len)
+{
+	struct fcookie *fc = f->cookie;
+	size_t ret;
+	size_t len2 = f->wpos - f->wbase;
+	if (fc->iofuncs.write == NULL) return -1;
+	if (len2) {
+		f->wpos = f->wbase;
+		if (cookiewrite(f, f->wpos, len2) < len2) return 0;
+	}
+	return fc->iofuncs.write(fc->cookie, (const char *) buf, len);
+}
+
+static off_t cookieseek(FILE *f, off_t off, int whence)
+{
+	struct fcookie *fc = f->cookie;
+	if (fc->iofuncs.seek) return fc->iofuncs.seek(fc->cookie, &off, whence);
+	return -1;
+}
+
+static int cookieclose(FILE *f)
+{
+	struct fcookie *fc = f->cookie;
+	if (fc->iofuncs.close) return fc->iofuncs.close(fc->cookie);
+	return 0;
+}
+
+FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t iofuncs)
+{
+	FILE *f;
+	struct fcookie *fc;
+
+	/* Check for valid initial mode character */
+	if (!strchr("rwa", *mode)) {
+		errno = EINVAL;
+		return 0;
+	}
+
+	/* Allocate FILE+fcookie+buffer or fail */
+	if (!(f=malloc(sizeof *f + sizeof *fc + UNGET + BUFSIZ))) return 0;
+
+	/* Zero-fill only the struct, not the buffer */
+	memset(f, 0, sizeof *f);
+
+	/* Impose mode restrictions */
+	if (!strchr(mode, '+')) f->flags = (*mode == 'r') ? F_NOWR : F_NORD;
+
+	/* Set up our fcookie */
+	fc = (void *)(f + 1);
+	fc->cookie = cookie;
+	fc->iofuncs.read = iofuncs.read;
+	fc->iofuncs.write = iofuncs.write;
+	fc->iofuncs.seek = iofuncs.seek;
+	fc->iofuncs.close = iofuncs.close;
+
+	f->fd = -1;
+	f->cookie = fc;
+	f->buf = (unsigned char *)f + sizeof *f + sizeof *fc + UNGET;
+	f->buf_size = BUFSIZ;
+	f->lbf = EOF;
+	f->lock = 0;
+
+	/* Initialize op ptrs. No problem if some are unneeded. */
+	f->read = cookieread;
+	f->write = cookiewrite;
+	f->seek = cookieseek;
+	f->close = cookieclose;
+
+	/* Add new FILE to open file list */
+	return __ofl_add(f);
+}
-- 
2.13.3



^ permalink raw reply	[flat|nested] 11+ messages in thread
* [PATCH] stdio: implement fopencookie(3)
@ 2017-10-10 23:27 William Pitcock
  0 siblings, 0 replies; 11+ messages in thread
From: William Pitcock @ 2017-10-10 23:27 UTC (permalink / raw)
  To: musl; +Cc: William Pitcock

The fopencookie(3) function allows the programmer to create a custom
stdio implementation, using four hook functions which operate on a
"cookie" data type.

Changelog:

v4:
- remove parameter names from header function declarations

v3:
- remove spurious `struct winsize`
- make f->lock unconditionally 0

v2:
- properly implement stdio buffering

v1:
- initial proof of concept
---
 include/stdio.h         |  9 +++++
 src/stdio/fopencookie.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)
 create mode 100644 src/stdio/fopencookie.c

diff --git a/include/stdio.h b/include/stdio.h
index 884d2e6a..da0563f6 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -182,6 +182,15 @@ int vasprintf(char **, const char *, __isoc_va_list);
 #ifdef _GNU_SOURCE
 char *fgets_unlocked(char *, int, FILE *);
 int fputs_unlocked(const char *, FILE *);
+
+typedef struct {
+	ssize_t (*read)(void *, char *, size_t);
+	ssize_t (*write)(void *, const char *, size_t);
+	int (*seek)(void *, off_t *, int);
+	int (*close)(void *);
+} cookie_io_functions_t;
+
+FILE *fopencookie(void *, const char *, cookie_io_functions_t);
 #endif
 
 #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
diff --git a/src/stdio/fopencookie.c b/src/stdio/fopencookie.c
new file mode 100644
index 00000000..baad2585
--- /dev/null
+++ b/src/stdio/fopencookie.c
@@ -0,0 +1,96 @@
+#define _GNU_SOURCE
+#include "stdio_impl.h"
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+struct fcookie {
+	void *cookie;
+	cookie_io_functions_t iofuncs;
+};
+
+static size_t cookieread(FILE *f, unsigned char *buf, size_t len)
+{
+	struct fcookie *fc = f->cookie;
+	size_t ret;
+	if (fc->iofuncs.read == NULL) return -1;
+	ret = fc->iofuncs.read(fc->cookie, (char *) buf, len);
+	if (ret == 0) f->flags |= F_EOF;
+	f->rpos = f->buf;
+	f->rend = f->buf + ret;
+	return ret;
+}
+
+static size_t cookiewrite(FILE *f, const unsigned char *buf, size_t len)
+{
+	struct fcookie *fc = f->cookie;
+	size_t ret;
+	size_t len2 = f->wpos - f->wbase;
+	if (fc->iofuncs.write == NULL) return -1;
+	if (len2) {
+		f->wpos = f->wbase;
+		if (cookiewrite(f, f->wpos, len2) < len2) return 0;
+	}
+	return fc->iofuncs.write(fc->cookie, (const char *) buf, len);
+}
+
+static off_t cookieseek(FILE *f, off_t off, int whence)
+{
+	struct fcookie *fc = f->cookie;
+	if (fc->iofuncs.seek) return fc->iofuncs.seek(fc->cookie, &off, whence);
+	return -1;
+}
+
+static int cookieclose(FILE *f)
+{
+	struct fcookie *fc = f->cookie;
+	if (fc->iofuncs.close) return fc->iofuncs.close(fc->cookie);
+	return 0;
+}
+
+FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t iofuncs)
+{
+	FILE *f;
+	struct fcookie *fc;
+
+	/* Check for valid initial mode character */
+	if (!strchr("rwa", *mode)) {
+		errno = EINVAL;
+		return 0;
+	}
+
+	/* Allocate FILE+fcookie+buffer or fail */
+	if (!(f=malloc(sizeof *f + sizeof *fc + UNGET + BUFSIZ))) return 0;
+
+	/* Zero-fill only the struct, not the buffer */
+	memset(f, 0, sizeof *f);
+
+	/* Impose mode restrictions */
+	if (!strchr(mode, '+')) f->flags = (*mode == 'r') ? F_NOWR : F_NORD;
+
+	/* Set up our fcookie */
+	fc = (void *)(f + 1);
+	fc->cookie = cookie;
+	fc->iofuncs.read = iofuncs.read;
+	fc->iofuncs.write = iofuncs.write;
+	fc->iofuncs.seek = iofuncs.seek;
+	fc->iofuncs.close = iofuncs.close;
+
+	f->fd = -1;
+	f->cookie = fc;
+	f->buf = (unsigned char *)f + sizeof *f + sizeof *fc + UNGET;
+	f->buf_size = BUFSIZ;
+	f->lbf = EOF;
+	f->lock = 0;
+
+	/* Initialize op ptrs. No problem if some are unneeded. */
+	f->read = cookieread;
+	f->write = cookiewrite;
+	f->seek = cookieseek;
+	f->close = cookieclose;
+
+	/* Add new FILE to open file list */
+	return __ofl_add(f);
+}
-- 
2.13.3



^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2017-10-11  5:51 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-05  6:48 [PATCH] stdio: implement fopencookie(3) William Pitcock
2017-10-05 10:10 ` Szabolcs Nagy
2017-10-10 18:03 William Pitcock
2017-10-10 18:51 ` Jens Gustedt
2017-10-10 20:56   ` Rich Felker
2017-10-10 21:40     ` Jens Gustedt
2017-10-11  2:08       ` Rich Felker
2017-10-11  5:51         ` Jens Gustedt
2017-10-10 22:58     ` Morten Welinder
2017-10-11  2:09       ` Rich Felker
2017-10-10 23:27 William Pitcock

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).