diff options
author | maximilian attems <max@stro.at> | 2011-08-31 00:45:57 +0200 |
---|---|---|
committer | maximilian attems <max@stro.at> | 2011-08-31 00:45:57 +0200 |
commit | 6c4e51f74c0c88be32e149b6293f578e1a394642 (patch) | |
tree | dd35bb0e7d4ca89c3ecc01161b231a333b75c18a | |
parent | ee8d5635fb901bd19d5919c9407c30db2e6a5051 (diff) | |
parent | dfc2cb14a2ca6055ecdd1059b03a36d296e30617 (diff) | |
download | klibc-6c4e51f74c0c88be32e149b6293f578e1a394642.tar.gz |
Merge remote-tracking branch 'origin/stdio' into maks/stdio
Fix up minor conflicts in:
usr/include/stdio.h
usr/klibc/Kbuild
-rw-r--r-- | usr/include/klibc/sysconfig.h | 11 | ||||
-rw-r--r-- | usr/include/stdio.h | 80 | ||||
-rw-r--r-- | usr/klibc/Kbuild | 9 | ||||
-rw-r--r-- | usr/klibc/exit.c | 2 | ||||
-rw-r--r-- | usr/klibc/libc_init.c | 4 | ||||
-rw-r--r-- | usr/klibc/stdio/fclose.c | 23 | ||||
-rw-r--r-- | usr/klibc/stdio/fdopen.c | 20 | ||||
-rw-r--r-- | usr/klibc/stdio/fflush.c | 45 | ||||
-rw-r--r-- | usr/klibc/stdio/fopen.c | 19 | ||||
-rw-r--r-- | usr/klibc/stdio/fputc.c | 24 | ||||
-rw-r--r-- | usr/klibc/stdio/fread.c | 53 | ||||
-rw-r--r-- | usr/klibc/stdio/fseek.c | 22 | ||||
-rw-r--r-- | usr/klibc/stdio/fwrite.c | 76 | ||||
-rw-r--r-- | usr/klibc/stdio/fxopen.c | 96 | ||||
-rw-r--r-- | usr/klibc/stdio/stdioint.h | 25 | ||||
-rw-r--r-- | usr/klibc/stdio/ungetc.c | 16 |
16 files changed, 479 insertions, 46 deletions
diff --git a/usr/include/klibc/sysconfig.h b/usr/include/klibc/sysconfig.h index a1c37fd2ed461..5fa9b60020954 100644 --- a/usr/include/klibc/sysconfig.h +++ b/usr/include/klibc/sysconfig.h @@ -107,6 +107,17 @@ /* + * _KLIBC_BUFSIZ: + * This is the size of an stdio buffer. By default this is + * _KLIBC_MALLOC_CHUNK_SIZE/4, which allows the three standard + * streams to fit inside a malloc chunk. + */ +#ifndef _KLIBC_BUFSIZ +# define _KLIBC_BUFSIZ (_KLIBC_MALLOC_CHUNK_SIZE >> 2) +#endif + + +/* * _KLIBC_SBRK_ALIGNMENT: * * This is the minimum alignment for the memory returned by diff --git a/usr/include/stdio.h b/usr/include/stdio.h index 2db63beebdb34..332254669e11a 100644 --- a/usr/include/stdio.h +++ b/usr/include/stdio.h @@ -6,21 +6,44 @@ #define _STDIO_H #include <klibc/extern.h> +#include <klibc/sysconfig.h> #include <stdarg.h> #include <stddef.h> #include <unistd.h> -/* This structure doesn't really exist, but it gives us something - to define FILE * with */ -struct _IO_file; +/* Unidirectional buffer */ +struct _IO_buf { + char *buf; /* Actual buffer */ +}; + +/* Actual FILE structure */ +struct _IO_file { + struct _IO_file *prev, *next; + off_t filepos; /* File position */ + char *buf; /* Buffer */ + int offset; /* Offset to data in buffer */ + int bytes; /* Data bytes in buffer */ + int bufsiz; /* Total size of buffer */ + int fd; /* Underlying file descriptor */ + int flags; /* Error, end of file */ +}; typedef struct _IO_file FILE; +enum _IO_file_flags { + _IO_FILE_FLAG_WRITE = 1, /* Buffer has write data */ + _IO_FILE_FLAG_READ = 2, /* Buffer has read data */ + _IO_FILE_FLAG_LINE_BUF = 4, /* Line buffered */ + _IO_FILE_FLAG_UNBUF = 8, /* Unbuffered */ + _IO_FILE_FLAG_EOF = 16, + _IO_FILE_FLAG_ERR = 32, +}; + #ifndef EOF # define EOF (-1) #endif #ifndef BUFSIZ -# define BUFSIZ 4096 +# define BUFSIZ _KLIBC_BUFSIZ #endif #define SEEK_SET 0 @@ -28,46 +51,22 @@ typedef struct _IO_file FILE; #define SEEK_END 2 /* - * Convert between a FILE * and a file descriptor. We don't actually - * have any in-memory data, so we just abuse the pointer itself to - * hold the data. Note, however, that for file descriptors, -1 is - * error and 0 is a valid value; for FILE *, NULL (0) is error and - * non-NULL are valid. + * Convert between a FILE * and a file descriptor. */ static __inline__ int fileno(FILE * __f) { - /* This should really be intptr_t, but size_t should be the same size */ - return (int)(size_t) __f - 1; + return __f->fd; } -/* This is a macro so it can be used as initializer */ -#define __create_file(__fd) ((FILE *)(size_t)((__fd) + 1)) - -#define stdin __create_file(0) -#define stdout __create_file(1) -#define stderr __create_file(2) +__extern FILE *stdin, *stdout, *stderr; __extern FILE *fopen(const char *, const char *); - -__static_inline FILE *fdopen(int __fd, const char *__m) -{ - (void)__m; - return __create_file(__fd); -} -__static_inline int fclose(FILE * __f) -{ - extern int close(int); - return close(fileno(__f)); -} -__static_inline int fseek(FILE * __f, off_t __o, int __w) -{ - extern off_t lseek(int, off_t, int); - return (lseek(fileno(__f), __o, __w) == (off_t) - 1) ? -1 : 0; -} +__extern FILE *fdopen(int, const char *); +__extern int fclose(FILE *); +__extern int fseek(FILE *, off_t, int); __static_inline off_t ftell(FILE * __f) { - extern off_t lseek(int, off_t, int); - return lseek(fileno(__f), 0, SEEK_CUR); + return __f->filepos; } __extern int fputs(const char *, FILE *); @@ -80,6 +79,7 @@ __extern int fgetc(FILE *); __extern char *fgets(char *, int, FILE *); #define getc(f) fgetc(f) #define getchar() fgetc(stdin) +__extern int ungetc(int, FILE *); __extern size_t _fread(void *, size_t, FILE *); __extern size_t _fwrite(const void *, size_t, FILE *); @@ -109,19 +109,13 @@ __extern int vsnprintf(char *, size_t n, const char *, va_list); __extern int asprintf(char **, const char *, ...); __extern int vasprintf(char **, const char *, va_list); -/* No buffering, so no flushing needed */ -__static_inline int fflush(FILE * __f) -{ - (void)__f; - return 0; -} - -/* stream errors are not kept track of by klibc implementation */ +/* XXX: stream errors should be kept track of */ __static_inline int ferror(FILE * __f) { (void)__f; return 0; } +__extern int fflush(FILE *); __extern int sscanf(const char *, const char *, ...); __extern int vsscanf(const char *, const char *, va_list); diff --git a/usr/klibc/Kbuild b/usr/klibc/Kbuild index c4f9ae250e489..e655d67b442c7 100644 --- a/usr/klibc/Kbuild +++ b/usr/klibc/Kbuild @@ -19,8 +19,8 @@ klib-y := vsnprintf.o snprintf.o vsprintf.o sprintf.o \ printf.o vprintf.o fprintf.o vfprintf.o perror.o \ statfs.o fstatfs.o umount.o \ creat.o open.o openat.o open_cloexec.o \ - fopen.o fread.o fread2.o fgetc.o fgets.o \ - fwrite.o fwrite2.o fputc.o fputs.o puts.o putchar.o \ + fread2.o fgetc.o fgets.o \ + fwrite2.o fputc.o fputs.o puts.o putchar.o \ sleep.o usleep.o strtotimespec.o strtotimeval.o \ raise.o abort.o assert.o alarm.o pause.o \ __signal.o sysv_signal.o bsd_signal.o siglist.o sigabbrev.o \ @@ -57,7 +57,10 @@ klib-y := vsnprintf.o snprintf.o vsprintf.o sprintf.o \ ctype/isxdigit.o ctype/tolower.o ctype/toupper.o \ userdb/getgrgid.o userdb/getgrnam.o userdb/getpwnam.o \ userdb/getpwuid.o userdb/root_group.o userdb/root_user.o \ - setmntent.o endmntent.o getmntent.o + setmntent.o endmntent.o getmntent.o \ + stdio/fclose.o stdio/fopen.o stdio/fdopen.o stdio/fxopen.o \ + stdio/fread.o stdio/fwrite.o stdio/fflush.o \ + stdio/fseek.o stdio/ungetc.o klib-$(CONFIG_KLIBC_ERRLIST) += errlist.o diff --git a/usr/klibc/exit.c b/usr/klibc/exit.c index 92f11c5e69e43..2368b07d793d2 100644 --- a/usr/klibc/exit.c +++ b/usr/klibc/exit.c @@ -6,6 +6,7 @@ #include <stdlib.h> #include <unistd.h> +#include <stdio.h> #include <sys/syscall.h> #include "atexit.h" @@ -25,6 +26,7 @@ __noreturn exit(int rv) } /* Handle any library destructors if we ever start using them... */ + fflush(NULL); _exit(rv); } diff --git a/usr/klibc/libc_init.c b/usr/klibc/libc_init.c index 55460ce88f8fb..8d18820df402f 100644 --- a/usr/klibc/libc_init.c +++ b/usr/klibc/libc_init.c @@ -39,6 +39,8 @@ struct auxentry { uintptr_t v; }; +extern void __init_stdio(void); + __noreturn __libc_init(uintptr_t * elfdata, void (*onexit) (void)) { int argc; @@ -102,6 +104,8 @@ __noreturn __libc_init(uintptr_t * elfdata, void (*onexit) (void)) #endif __page_shift = page_shift; + __init_stdio(); + environ = envp; exit(MAIN(argc, argv, envp)); } diff --git a/usr/klibc/stdio/fclose.c b/usr/klibc/stdio/fclose.c new file mode 100644 index 0000000000000..682385ebe29b9 --- /dev/null +++ b/usr/klibc/stdio/fclose.c @@ -0,0 +1,23 @@ +/* + * fclose.c + */ + +#include "stdioint.h" + +int fclose(FILE *f) +{ + int rv; + + fflush(f); + + rv = close(f->fd); + + /* Remove from linked list */ + f->next->prev = f->prev; + f->prev->next = f->next; + + free(f->buf); + free(f); + + return rv; +} diff --git a/usr/klibc/stdio/fdopen.c b/usr/klibc/stdio/fdopen.c new file mode 100644 index 0000000000000..99f3a807db7e1 --- /dev/null +++ b/usr/klibc/stdio/fdopen.c @@ -0,0 +1,20 @@ +/* + * fdopen.c + */ + +#include "stdioint.h" + +FILE *fdopen(int fd, const char *mode) +{ + int flags = __parse_open_mode(mode); + int oldflags; + + if (fcntl(fd, F_GETFL, &oldflags)) + return NULL; + + oldflags = (oldflags & ~O_APPEND) | (flags & O_APPEND); + if (fcntl(fd, F_SETFL, &oldflags)) + return NULL; + + return __fxopen(fd, flags, 0); +} diff --git a/usr/klibc/stdio/fflush.c b/usr/klibc/stdio/fflush.c new file mode 100644 index 0000000000000..434fc51c3d125 --- /dev/null +++ b/usr/klibc/stdio/fflush.c @@ -0,0 +1,45 @@ +/* + * fflush.c + */ + +#include "stdioint.h" + +int fflush(FILE *f) +{ + ssize_t rv; + char *p; + + if (!f) { + int err = 0; + + for (f = __stdio_headnode.next; f != &__stdio_headnode; + f = f->next) + err |= fflush(f); + return err; + } + + if (!f->flags & _IO_FILE_FLAG_WRITE) + return 0; + + p = f->buf; + while (f->bytes) { + rv = write(f->fd, p, f->bytes); + if (rv == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + f->flags |= _IO_FILE_FLAG_ERR; + return EOF; + } else if (rv == 0) { + /* EOF on output? */ + f->flags |= _IO_FILE_FLAG_EOF; + return EOF; + } + + p += rv; + f->bytes -= rv; + } + f->offset = _IO_UNGET_SLOP; + f->flags &= ~_IO_FILE_FLAG_WRITE; + + return 0; +} diff --git a/usr/klibc/stdio/fopen.c b/usr/klibc/stdio/fopen.c new file mode 100644 index 0000000000000..475620fe6da2c --- /dev/null +++ b/usr/klibc/stdio/fopen.c @@ -0,0 +1,19 @@ +/* + * fopen.c + */ + +#include "stdioint.h" + +extern int __parse_open_mode(const char *); + +FILE *fopen(const char *file, const char *mode) +{ + int flags = __parse_open_mode(mode); + int fd; + + fd = open(file, flags, 0666); + if (fd < 0) + return NULL; + + return __fxopen(fd, flags, 1); +} diff --git a/usr/klibc/stdio/fputc.c b/usr/klibc/stdio/fputc.c new file mode 100644 index 0000000000000..8fd3452261b2f --- /dev/null +++ b/usr/klibc/stdio/fputc.c @@ -0,0 +1,24 @@ +/* + * fputc.c + */ + +#include "stdioint.h" + +int __fputc(int c, FILE *f) +{ + if (f->bytes >= f->bufsiz) + fflush(f); + + *f->buf++ = c; + f->flags |= _IO_FILE_FLAG_WRITE; + + if (f->flags & _IO_FILE_LINE_BUF && c == '\n') + fflush(f); +} + +int fputc(int c, FILE *f) +{ + __fputc(c, f); + if (f->flags & _IO_FILE_UNBUF) + fflush(f); +} diff --git a/usr/klibc/stdio/fread.c b/usr/klibc/stdio/fread.c new file mode 100644 index 0000000000000..b318dac506ad6 --- /dev/null +++ b/usr/klibc/stdio/fread.c @@ -0,0 +1,53 @@ +/* + * fread.c + */ + +#include <string.h> +#include "stdioint.h" + +size_t _fread(void *buf, size_t count, FILE *f) +{ + size_t bytes = 0; + size_t nb; + char *p = buf; + ssize_t rv; + + /* Note: one could avoid double-buffering large reads. */ + + for (;;) { + nb = f->bytes; + nb = (count < nb) ? count : nb; + if (nb) { + memcpy(p, f->buf+f->offset, nb); + f->offset += nb; + f->bytes -= nb; + p += nb; + count -= nb; + bytes += nb; + f->filepos += nb; + if (!f->bytes) + f->flags &= ~_IO_FILE_FLAG_READ; + } + + if (!count) + break; /* Done... */ + + /* If we get here, f->ibuf must be empty */ + f->offset = _IO_UNGET_SLOP; + + rv = read(f->fd, f->buf+_IO_UNGET_SLOP, BUFSIZ); + if (rv == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + f->flags |= _IO_FILE_FLAG_ERR; + return bytes; + } else if (rv == 0) { + f->flags |= _IO_FILE_FLAG_EOF; + return bytes; + } + + f->bytes = rv; + f->flags |= _IO_FILE_FLAG_READ; + } + return bytes; +} diff --git a/usr/klibc/stdio/fseek.c b/usr/klibc/stdio/fseek.c new file mode 100644 index 0000000000000..1a2ced3eb4bd7 --- /dev/null +++ b/usr/klibc/stdio/fseek.c @@ -0,0 +1,22 @@ +/* + * fseek.c + */ + +#include "stdioint.h" + +__extern int fseek(FILE *f, off_t where, int whence) +{ + off_t rv; + + fflush(f); + + rv = lseek(f->fd, where, whence); + if (rv != -1) { + f->filepos = rv; + f->bytes = 0; + f->flags &= ~_IO_FILE_FLAG_READ; + return 0; + } else { + return -1; + } +} diff --git a/usr/klibc/stdio/fwrite.c b/usr/klibc/stdio/fwrite.c new file mode 100644 index 0000000000000..7ad49d24162d7 --- /dev/null +++ b/usr/klibc/stdio/fwrite.c @@ -0,0 +1,76 @@ +/* + * fwrite.c + */ + +#include <string.h> +#include "stdioint.h" + +static size_t fwrite_noflush(const void *buf, size_t count, FILE *f) +{ + size_t bytes = 0; + size_t nb; + const char *p = buf; + + /* Note: one could avoid double-buffering large writes. */ + + for (;;) { + nb = f->bufsiz - f->bytes; + nb = (count < nb) ? count : nb; + if (nb) { + memcpy(f->buf+f->bytes, p, nb); + p += nb; + f->bytes += nb; + count -= nb; + bytes += nb; + f->filepos += nb; + f->flags |= _IO_FILE_FLAG_WRITE; + } + + if (!count) + break; /* Done... */ + + /* If we get here, the buffer must be full */ + if (fflush(f)) + break; + } + return bytes; +} + +size_t _fwrite(const void *buf, size_t count, FILE *f) +{ + size_t bytes = 0; + size_t pf_len, pu_len; + const char *p = buf; + + /* We divide the data into two chunks, flushed (pf) + and unflushed (pu) depending on buffering mode + and contents. */ + + if (f->flags & _IO_FILE_FLAG_UNBUF) { + pf_len = 0; + pu_len = count; + } else if (f->flags & _IO_FILE_FLAG_LINE_BUF) { + pf_len = count; + pu_len = 0; + + while (pf_len && p[pf_len-1] != '\n') { + pf_len--; + pu_len++; + } + } else { + pf_len = 0; + pu_len = count; + } + + if (pf_len) { + bytes = fwrite_noflush(p, pf_len, f); + p += bytes; + if (fflush(f) || bytes != pf_len) + return bytes; + } + + if (pu_len) + bytes += fwrite_noflush(p, pu_len, f); + + return bytes; +} diff --git a/usr/klibc/stdio/fxopen.c b/usr/klibc/stdio/fxopen.c new file mode 100644 index 0000000000000..7c596ec0da925 --- /dev/null +++ b/usr/klibc/stdio/fxopen.c @@ -0,0 +1,96 @@ +/* + * fxopen.c + * + * Common code between fopen(), fdopen() and the standard descriptors. + */ + +#include "stdioint.h" + +FILE *stdin, *stdout, *stderr; + +/* Doubly-linked list of all stdio structures */ +struct _IO_file __stdio_headnode = +{ + .prev = &__stdio_headnode, + .next = &__stdio_headnode, +}; + +/* This depends on O_RDONLY == 0, O_WRONLY == 1, O_RDWR == 2 */ +int __parse_open_mode(const char *mode) +{ + int plus = 0; + int flags = O_RDONLY; + + while (*mode) { + switch (*mode++) { + case 'r': + flags = O_RDONLY; + break; + case 'w': + flags = O_WRONLY | O_CREAT | O_TRUNC; + break; + case 'a': + flags = O_WRONLY | O_CREAT | O_APPEND; + break; + case '+': + plus = 1; + break; + } + } + + if (plus) + flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR; + + return flags; +} + +FILE *__fxopen(int fd, int flags, int close_on_err) +{ + FILE *f = NULL; + + f = malloc(sizeof *f); + if (!f) + goto err; + + f->fd = fd; + f->filepos = lseek(fd, 0, SEEK_CUR); + + f->buf = malloc(BUFSIZ + _IO_UNGET_SLOP); + if (!f->buf) + goto err; + + f->bufsiz = BUFSIZ; + f->offset = _IO_UNGET_SLOP; + f->bytes = 0; /* No bytes in buffer */ + f->flags = isatty(fd) ? _IO_FILE_FLAG_LINE_BUF : 0; + + /* Insert into linked list */ + f->prev = &__stdio_headnode; + f->next = __stdio_headnode.next; + f->next->prev = f; + __stdio_headnode.next = f; + + return f; + +err: + if (f) { + free(f->buf); + free(f); + } + if (close_on_err) + close(fd); + errno = ENOMEM; + return NULL; +} + +void __init_stdio(void) +{ + stdin = __fxopen(0, O_RDONLY, 0); + stdin->flags = _IO_FILE_FLAG_LINE_BUF; + + stdout = __fxopen(1, O_WRONLY|O_TRUNC, 0); + stdout->flags = _IO_FILE_FLAG_LINE_BUF; + + stderr = __fxopen(2, O_WRONLY|O_TRUNC, 0); + stderr->flags = _IO_FILE_FLAG_UNBUF; +} diff --git a/usr/klibc/stdio/stdioint.h b/usr/klibc/stdio/stdioint.h new file mode 100644 index 0000000000000..ad2458924f2da --- /dev/null +++ b/usr/klibc/stdio/stdioint.h @@ -0,0 +1,25 @@ +/* + * stdioint.h + * + * stdio internals + */ + +#ifndef USR_KLIBC_STDIO_STDIOINT_H +#define USR_KLIBC_STDIO_STDIOINT_H + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +/* Assign this much extra to the input buffer in case of ungetc() */ +#define _IO_UNGET_SLOP 32 + +__extern int __parse_open_mode(const char *mode); +__extern FILE *__fxopen(int fd, int flags, int close_on_err); +__extern int __fputc(int c, FILE *f); + +__extern struct _IO_file __stdio_headnode; + +#endif /* USR_KLIBC_STDIO_STDIOINT_H */ diff --git a/usr/klibc/stdio/ungetc.c b/usr/klibc/stdio/ungetc.c new file mode 100644 index 0000000000000..b2a304cdfb803 --- /dev/null +++ b/usr/klibc/stdio/ungetc.c @@ -0,0 +1,16 @@ +/* + * ungetc.c + */ + +#include "stdioint.h" + +int ungetc(int c, FILE *f) +{ + if (f->flags & _IO_FILE_FLAG_WRITE || f->offset <= 0) + return EOF; + + f->buf[--f->offset] = c; + f->bytes++; + f->flags |= _IO_FILE_FLAG_READ; + return c; +} |