diff options
author | H. Peter Anvin <hpa@zytor.com> | 2009-08-09 16:13:55 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-08-09 16:45:05 -0700 |
commit | f614a40876843b7de58d8410b47c8c68e2ab6992 (patch) | |
tree | 7d0d0d8e42a0a2a019bedb869b58699c208267e1 | |
parent | 8b0f75f79811a30cd3f8460e305c6eea82f288a0 (diff) | |
download | bak.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.h | 2 | ||||
-rw-r--r-- | com32/include/unistd.h | 2 | ||||
-rw-r--r-- | com32/lib/Makefile | 4 | ||||
-rw-r--r-- | com32/lib/sys/file.h | 14 | ||||
-rw-r--r-- | com32/lib/sys/fileread.c | 4 | ||||
-rw-r--r-- | com32/lib/sys/ftell.c | 2 | ||||
-rw-r--r-- | com32/lib/sys/read.c | 20 | ||||
-rw-r--r-- | com32/lib/sys/unread.c | 55 | ||||
-rw-r--r-- | com32/lib/ungetc.c | 18 |
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; +} |