aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-08-09 16:13:55 -0700
committerH. Peter Anvin <hpa@zytor.com>2009-08-09 16:45:05 -0700
commitf614a40876843b7de58d8410b47c8c68e2ab6992 (patch)
tree7d0d0d8e42a0a2a019bedb869b58699c208267e1
parent8b0f75f79811a30cd3f8460e305c6eea82f288a0 (diff)
downloadbak.git-f614a40876843b7de58d8410b47c8c68e2ab6992.tar.gz
bak.git-f614a40876843b7de58d8410b47c8c68e2ab6992.tar.xz
bak.git-f614a40876843b7de58d8410b47c8c68e2ab6992.zip
lib: add unread() syscall; use it to implement ungetc()
Add an unread() syscall, which allows some read bytes to be pushed back into the read buffer. This allows us to read a header from a file and then push it back. This also makes ungetc() implementable. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--com32/include/stdio.h2
-rw-r--r--com32/include/unistd.h2
-rw-r--r--com32/lib/Makefile4
-rw-r--r--com32/lib/sys/file.h14
-rw-r--r--com32/lib/sys/fileread.c4
-rw-r--r--com32/lib/sys/ftell.c2
-rw-r--r--com32/lib/sys/read.c20
-rw-r--r--com32/lib/sys/unread.c55
-rw-r--r--com32/lib/ungetc.c18
9 files changed, 114 insertions, 7 deletions
diff --git a/com32/include/stdio.h b/com32/include/stdio.h
index f37bdd9e..cbba55e8 100644
--- a/com32/include/stdio.h
+++ b/com32/include/stdio.h
@@ -88,6 +88,8 @@ __extern size_t fwrite(const void *, size_t, size_t, FILE *);
/* No seek, but we can tell */
__extern long ftell(FILE *);
+__extern int ungetc(int, FILE *);
+
__extern int printf(const char *, ...);
__extern int vprintf(const char *, va_list);
__extern int fprintf(FILE *, const char *, ...);
diff --git a/com32/include/unistd.h b/com32/include/unistd.h
index c0b52d60..8b1b93d5 100644
--- a/com32/include/unistd.h
+++ b/com32/include/unistd.h
@@ -18,6 +18,8 @@ __extern int close(int);
__extern ssize_t read(int, void *, size_t);
__extern ssize_t write(int, const void *, size_t);
+__extern ssize_t unread(int, const void *, size_t);
+
__extern int isatty(int);
__extern int getscreensize(int, int *, int *);
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index 1806ec20..f00b27a9 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -10,7 +10,7 @@ include MCONFIG
LIBOBJS = \
abort.o atexit.o atoi.o atol.o atoll.o calloc.o creat.o \
ctypes.o errno.o fgetc.o fgets.o fopen.o fprintf.o fputc.o \
- fclose.o putchar.o setjmp.o \
+ fclose.o putchar.o ungetc.o setjmp.o \
fputs.o fread2.o fread.o free.o fwrite2.o fwrite.o getopt.o \
lrand48.o malloc.o stack.o memccpy.o memchr.o memcmp.o \
memcpy.o mempcpy.o memmem.o memmove.o memset.o memswap.o \
@@ -38,7 +38,7 @@ LIBOBJS = \
sys/entry.o sys/exit.o sys/argv.o sys/times.o \
sys/fileinfo.o sys/opendev.o sys/read.o sys/write.o sys/ftell.o \
sys/close.o sys/open.o sys/fileread.o sys/fileclose.o \
- sys/openmem.o \
+ sys/openmem.o sys/unread.o \
sys/isatty.o sys/fstat.o \
\
sys/zfile.o sys/zfopen.o \
diff --git a/com32/lib/sys/file.h b/com32/lib/sys/file.h
index 12492264..4bcca2e5 100644
--- a/com32/lib/sys/file.h
+++ b/com32/lib/sys/file.h
@@ -69,7 +69,7 @@ struct output_dev {
ssize_t (*write)(struct file_info *, const void *, size_t);
int (*close)(struct file_info *);
int (*open)(struct file_info *);
- const struct output_dev *fallback; /* Fallback option for certain consoles */
+ const struct output_dev *fallback; /* Fallback option for some consoles */
};
/* File structure */
@@ -97,9 +97,21 @@ struct file_info {
char *datap; /* Current data pointer */
void *pvt; /* Private pointer for driver */
char *buf; /* Data buffer */
+ size_t unread_bytes; /* Valid bytes in unread_buf */
+ char unread_buf[64]; /* unread() data */
} i;
};
+static inline size_t unread_free(struct file_info *fp)
+{
+ return sizeof fp->i.unread_buf - fp->i.unread_bytes;
+}
+
+static inline char *unread_data(struct file_info *fp)
+{
+ return fp->i.unread_buf + unread_free(fp);
+}
+
extern struct file_info __file_info[NFILES];
/* Line input discipline */
diff --git a/com32/lib/sys/fileread.c b/com32/lib/sys/fileread.c
index 54ff7115..f1fd3eb1 100644
--- a/com32/lib/sys/fileread.c
+++ b/com32/lib/sys/fileread.c
@@ -58,12 +58,12 @@ int __file_get_block(struct file_info *fp)
fp->i.filedes = oreg.esi.w[0];
fp->i.nbytes = oreg.ecx.l;
fp->i.datap = fp->i.buf;
- memcpy(fp->i.buf, __com32.cs_bounce, fp->i.nbytes);
+ memcpy(fp->i.datap, __com32.cs_bounce, fp->i.nbytes);
return 0;
}
-ssize_t __file_read(struct file_info * fp, void *buf, size_t count)
+ssize_t __file_read(struct file_info *fp, void *buf, size_t count)
{
char *bufp = buf;
ssize_t n = 0;
diff --git a/com32/lib/sys/ftell.c b/com32/lib/sys/ftell.c
index 5c1a9442..d8090087 100644
--- a/com32/lib/sys/ftell.c
+++ b/com32/lib/sys/ftell.c
@@ -12,5 +12,5 @@ long ftell(FILE * stream)
int fd = fileno(stream);
struct file_info *fp = &__file_info[fd];
- return fp->i.offset;
+ return fp->i.offset - fp->i.unread_bytes;
}
diff --git a/com32/lib/sys/read.c b/com32/lib/sys/read.c
index e097ade1..388f6987 100644
--- a/com32/lib/sys/read.c
+++ b/com32/lib/sys/read.c
@@ -41,11 +41,29 @@
ssize_t read(int fd, void *buf, size_t count)
{
struct file_info *fp = &__file_info[fd];
+ size_t n0, n1;
if (fd >= NFILES || !fp->iop) {
errno = EBADF;
return -1;
}
- return fp->iop->read(fp, buf, count);
+ if (!count)
+ return 0;
+
+ n0 = min(fp->i.unread_bytes, count);
+ if (n0) {
+ memcpy(buf, unread_data(fp), n0);
+ fp->i.unread_bytes -= n0;
+ count -= n0;
+ if (!count)
+ return n0;
+ }
+
+ n1 = fp->iop->read(fp, buf, count);
+
+ if (n1 == -1 && n0 > 0)
+ return n0;
+ else
+ return n0 + n1;
}
diff --git a/com32/lib/sys/unread.c b/com32/lib/sys/unread.c
new file mode 100644
index 00000000..08f8b3bf
--- /dev/null
+++ b/com32/lib/sys/unread.c
@@ -0,0 +1,55 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * unread.c
+ *
+ * "Unreading" from a file descriptor
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <com32.h>
+#include <minmax.h>
+#include <klibc/compiler.h>
+#include "file.h"
+
+ssize_t unread(int fd, const void *buf, size_t count)
+{
+ struct file_info *fp = &__file_info[fd];
+
+ if (fd >= NFILES || !fp->iop) {
+ errno = EBADF;
+ return -1;
+ }
+
+ count = min(count, unread_free(fp));
+ fp->i.unread_bytes += count;
+ memcpy(unread_data(fp), buf, count);
+
+ return count;
+}
diff --git a/com32/lib/ungetc.c b/com32/lib/ungetc.c
new file mode 100644
index 00000000..b8ffca98
--- /dev/null
+++ b/com32/lib/ungetc.c
@@ -0,0 +1,18 @@
+/*
+ * ungetc.c
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+
+int ungetc(int c, FILE *f)
+{
+ unsigned char ch = c;
+
+ if (unread(fileno(f), &ch, 1) == 1)
+ return ch;
+ else
+ return EOF;
+}