From 1756cc5943aa545f2f18fff60d56ad0886ef6145 Mon Sep 17 00:00:00 2001
From: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date: Mon, 27 Apr 2009 20:14:06 +1000
Subject: libbb/strbuf_file: stdio emulation layer for handling with Winsock
 handles

not really robust, but enough to make wget works
---
 include/strbuf_file.h |  69 +++++++++++++++++++++++++++++
 libbb/Kbuild          |   1 +
 libbb/strbuf_file.c   | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 189 insertions(+)
 create mode 100644 include/strbuf_file.h
 create mode 100644 libbb/strbuf_file.c

diff --git a/include/strbuf_file.h b/include/strbuf_file.h
new file mode 100644
index 000000000..73eff9193
--- /dev/null
+++ b/include/strbuf_file.h
@@ -0,0 +1,69 @@
+#include "strbuf.h"
+
+struct strbuf_file {
+	struct strbuf input;
+	int has_error;
+	int fd;
+};
+
+struct strbuf_file *sfdopen(int fd, const char *mode);
+int sfclose(struct strbuf_file *sf);
+int sfprintf(struct strbuf_file *sf, const char *fmt, ...);
+void sfclearerr(struct strbuf_file *sf);
+int sfread(char *buf, int size, int n, struct strbuf_file *sf);
+char *sfgets(char *buf, int size, struct strbuf_file *sf);
+int sfgetc(struct strbuf_file *sf);
+
+#ifdef REPLACE_STDIO
+
+#ifdef FILE
+#undef FILE
+#endif
+#define FILE struct strbuf_file
+
+#ifdef fdopen
+#undef fdopen
+#endif
+#define fdopen(fd,mode) sfdopen(fd,mode)
+
+#ifdef fclose
+#undef fclose
+#endif
+#define fclose(fp) sfclose(fp)
+
+#ifdef fprintf
+#undef fprintf
+#endif
+#define fprintf sfprintf
+
+#ifdef fread
+#undef fread
+#endif
+#define fread(buf,s,n,fp) sfread(buf,s,n,fp)
+
+#ifdef clearerr
+#undef clearerr
+#endif
+#define clearerr(fp) sfclearerr(fp)
+
+#ifdef ferror
+#undef ferror
+#endif
+#define ferror(fp) ((fp)->has_error)
+
+#ifdef fgets
+#undef fgets
+#endif
+#define fgets(buf,n,fp) sfgets(buf,n,fp)
+
+#ifdef getc
+#undef getc
+#endif
+#define getc(fp) sfgetc(fp)
+
+#ifdef fflush
+#undef fflush
+#endif
+#define fflush(fp) 0
+
+#endif
diff --git a/libbb/Kbuild b/libbb/Kbuild
index 4c8f542fc..dca58d6f7 100644
--- a/libbb/Kbuild
+++ b/libbb/Kbuild
@@ -136,6 +136,7 @@ lib-$(CONFIG_MINGW32) += regex.o
 lib-$(CONFIG_MINGW32) += run-command.o
 lib-$(CONFIG_MINGW32) += setenv.o
 lib-$(CONFIG_MINGW32) += strbuf.o
+lib-$(CONFIG_MINGW32) += strbuf_file.o
 lib-$(CONFIG_MINGW32) += strlcpy.o
 lib-$(CONFIG_MINGW32) += trace.o
 lib-$(CONFIG_MINGW32) += usage.o
diff --git a/libbb/strbuf_file.c b/libbb/strbuf_file.c
new file mode 100644
index 000000000..fb2ba7966
--- /dev/null
+++ b/libbb/strbuf_file.c
@@ -0,0 +1,119 @@
+#include "libbb.h"
+#include "strbuf_file.h"
+
+struct strbuf_file *sfdopen(int fd, const char *mode)
+{
+	struct strbuf_file *s;
+
+	s = xmalloc(sizeof(*s));
+	strbuf_init(&s->input, 0);
+	s->has_error = 0;
+	s->fd = fd;
+	return s;
+}
+
+int sfclose(struct strbuf_file *sf)
+{
+	strbuf_release(&sf->input);
+	close(sf->fd);
+	free(sf);
+	return 0;
+}
+
+int sfprintf(struct strbuf_file *sf, const char *fmt, ...)
+{
+	int len;
+	va_list ap;
+	struct strbuf sb = STRBUF_INIT;
+
+	strbuf_grow(&sb, 64);
+	va_start(ap, fmt);
+	len = vsnprintf(sb.buf + sb.len, sb.alloc - sb.len, fmt, ap);
+	va_end(ap);
+	if (len < 0)
+		die("your vsnprintf is broken");
+	if (len > strbuf_avail(&sb)) {
+		strbuf_grow(&sb, len);
+		va_start(ap, fmt);
+		len = vsnprintf(sb.buf + sb.len, sb.alloc - sb.len, fmt, ap);
+		va_end(ap);
+		if (len > strbuf_avail(&sb)) {
+			die("this should not happen, your snprintf is broken");
+		}
+	}
+	strbuf_setlen(&sb, sb.len + len);
+	len = write(sf->fd, sb.buf, sb.len);
+	strbuf_release(&sb);
+	return len;
+}
+
+void sfclearerr(struct strbuf_file *sf)
+{
+	sf->has_error = 0;
+}
+
+int sfread(char *buf, int size, int n, struct strbuf_file *sf)
+{
+	int avail = size * n;
+	int len = avail > sf->input.len ? sf->input.len : avail;
+	char *p;
+	struct strbuf *sb = &sf->input;
+
+	if (len) {
+		memcpy(buf, sb->buf, len);
+		strbuf_setlen(sb, sb->len - len);
+		avail -= len;
+	}
+
+	p = buf + len;
+	while ((len = read(sf->fd, p, avail)) > 0) {
+		p += len;
+		avail -= len;
+		if (!avail)
+			break;
+	}
+	if  (len == -1)
+		sf->has_error = 1;
+	/* just in case we have some leftover */
+	if ((p-buf) % size) {
+		len = (p-buf) % size;
+		strbuf_grow(sb, len);
+		strbuf_add(sb, p-len, len);
+	}
+	return (p-buf) / size;
+}
+
+int sfgetc(struct strbuf_file *sf)
+{
+	int ret;
+	char ch;
+	if (sf->input.len) {
+		ret = sf->input.buf[0];
+		memcpy(sf->input.buf, sf->input.buf+1, sf->input.len);
+		sf->input.len--;
+		return ret;
+	}
+	ret = read(sf->fd, &ch, 1);
+	if (ret > 0)
+		return ch;
+	if (ret == -1)
+		sf->has_error = 1;
+	return EOF;
+}
+
+char *sfgets(char *buf, int size, struct strbuf_file *sf)
+{
+	char *p = buf;
+	int ch = -1;
+	while (size > 1 && (ch = sfgetc(sf)) != EOF) {
+		*p++ = ch;
+		size--;
+		if (ch == '\n')
+			break;
+	}
+	if (p > buf && size > 0) {
+		*p++ = '\0';
+		return buf;
+	}
+	return NULL;
+}
-- 
cgit v1.2.3-55-g6feb