From d7c54161b2d86ad00aee8825ddc26aee727d7c45 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Thu, 27 Feb 2014 20:57:14 +0100 Subject: [PATCH] Revise stdio implementation. --- libc/Makefile | 10 + libc/include/FILE.h | 26 ++- libc/include/stdio.h | 11 + libc/stdio/clearerr_unlocked.cpp | 5 +- libc/stdio/fdio.cpp | 219 ++------------------ libc/stdio/fdio.h | 31 ++- libc/stdio/fdio_install_fd.cpp | 71 +++++++ libc/stdio/fdio_install_path.cpp | 58 ++++++ libc/stdio/fdopen.cpp | 37 ++++ libc/stdio/feof_unlocked.cpp | 9 +- libc/stdio/ferror_unlocked.cpp | 6 +- libc/stdio/fflush_stop_reading_unlocked.cpp | 42 ++-- libc/stdio/fflush_stop_writing_unlocked.cpp | 41 +++- libc/stdio/fflush_unlocked.cpp | 8 +- libc/stdio/fgetc_unlocked.cpp | 50 +++-- libc/stdio/fileno_unlocked.cpp | 9 +- libc/stdio/fopen.cpp | 37 ++++ libc/stdio/fparsemode.cpp | 54 +++++ libc/stdio/fputc_unlocked.cpp | 29 ++- libc/stdio/fread_unlocked.cpp | 47 +++-- libc/stdio/freadable_unlocked.cpp | 4 +- libc/stdio/freading_unlocked.cpp | 6 +- libc/stdio/freopen.cpp | 2 +- libc/stdio/fseeko_unlocked.cpp | 12 +- libc/stdio/fsetdefaultbuf_unlocked.cpp | 29 +-- libc/stdio/fseterr_unlocked.cpp | 5 +- libc/stdio/ftello_unlocked.cpp | 17 +- libc/stdio/fwritable_unlocked.cpp | 4 +- libc/stdio/fwrite_unlocked.cpp | 45 +++- libc/stdio/fwriting_unlocked.cpp | 6 +- libc/stdio/getchar.cpp | 33 +++ libc/stdio/getchar_unlocked.cpp | 30 +++ libc/stdio/popen.cpp | 131 +++--------- libc/stdio/putchar.cpp | 33 +++ libc/stdio/putchar_unlocked.cpp | 30 +++ libc/stdio/puts.cpp | 30 +++ libc/stdio/setvbuf_unlocked.cpp | 4 +- libc/stdio/stdio.cpp | 78 +++---- libc/stdio/ungetc_unlocked.cpp | 24 ++- libc/stdio/vfprintf_unlocked.cpp | 8 +- libc/stdio/vfscanf_unlocked.cpp | 4 + 41 files changed, 815 insertions(+), 520 deletions(-) create mode 100644 libc/stdio/fdio_install_fd.cpp create mode 100644 libc/stdio/fdio_install_path.cpp create mode 100644 libc/stdio/fdopen.cpp create mode 100644 libc/stdio/fopen.cpp create mode 100644 libc/stdio/fparsemode.cpp create mode 100644 libc/stdio/getchar.cpp create mode 100644 libc/stdio/getchar_unlocked.cpp create mode 100644 libc/stdio/putchar.cpp create mode 100644 libc/stdio/putchar_unlocked.cpp create mode 100644 libc/stdio/puts.cpp diff --git a/libc/Makefile b/libc/Makefile index 34d40281..cf8a9620 100644 --- a/libc/Makefile +++ b/libc/Makefile @@ -92,6 +92,7 @@ stdio/flbf_unlocked.o \ stdio/flockfile.o \ stdio/flushlbf.o \ stdio/fnewfile.o \ +stdio/fparsemode.o \ stdio/fpending.o \ stdio/fpending_unlocked.o \ stdio/fprintf_unlocked.o \ @@ -385,20 +386,29 @@ signal/sigpending.o \ signal/sigprocmask.o \ signal/sigsuspend.o \ stdio/fcloseall.o \ +stdio/fdio_install_fd.o \ +stdio/fdio_install_path.o \ stdio/fdio.o \ +stdio/fdopen.o \ stdio/fgetpos.o \ stdio/fileno.o \ +stdio/fopen.o \ stdio/fpipe.o \ stdio/fprintf.o \ stdio/freopen.o \ stdio/fsetpos.o \ +stdio/getchar.o \ +stdio/getchar_unlocked.o \ stdio/getc.o \ stdio/getc_unlocked.o \ stdio/perror.o \ stdio/popen.o \ stdio/printf.o \ +stdio/putchar.o \ +stdio/putchar_unlocked.o \ stdio/putc.o \ stdio/putc_unlocked.o \ +stdio/puts.o \ stdio/removeat.o \ stdio/remove.o \ stdio/renameat.o \ diff --git a/libc/include/FILE.h b/libc/include/FILE.h index e9164ecd..3b505a18 100644 --- a/libc/include/FILE.h +++ b/libc/include/FILE.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -44,6 +44,11 @@ typedef __off_t off_t; #include #endif +#ifndef __ssize_t_defined +#define __ssize_t_defined +typedef __ssize_t ssize_t; +#endif + #ifndef __FILE_defined #define __FILE_defined typedef struct FILE FILE; @@ -54,8 +59,12 @@ typedef struct FILE FILE; #define _FILE_LAST_WRITE (1<<2) #define _FILE_LAST_READ (1<<3) #define _FILE_AUTO_LOCK (1<<4) -#define _FILE_STREAM (1<<5) -#define _FILE_BUFFER_OWNED (1<<6) +#define _FILE_BUFFER_OWNED (1<<5) +#define _FILE_STATUS_ERROR (1<<6) +#define _FILE_STATUS_EOF (1<<7) +#define _FILE_READABLE (1<<8) +#define _FILE_WRITABLE (1<<9) + #define _FILE_MAX_PUSHBACK 8 struct FILE @@ -69,14 +78,9 @@ struct FILE void* user; void* free_user; int (*reopen_func)(void* user, const char* mode); - size_t (*read_func)(void* ptr, size_t size, size_t nmemb, void* user); - size_t (*write_func)(const void* ptr, size_t size, size_t nmemb, void* user); - int (*seek_func)(void* user, off_t offset, int whence); - off_t (*tell_func)(void* user); - void (*seterr_func)(void* user); - void (*clearerr_func)(void* user); - int (*eof_func)(void* user); - int (*error_func)(void* user); + ssize_t (*read_func)(void* user, void* ptr, size_t size); + ssize_t (*write_func)(void* user, const void* ptr, size_t size); + off_t (*seek_func)(void* user, off_t offset, int whence); int (*fileno_func)(void* user); int (*close_func)(void* user); void (*free_func)(void* free_user, struct FILE* fp); diff --git a/libc/include/stdio.h b/libc/include/stdio.h index 564ef395..4c83b532 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -215,6 +215,16 @@ FILE* open_memstream(char** bufp, size_t* sizep); #endif #if defined(_SORTIX_SOURCE) + +#define FILE_MODE_READ (1 << 0) +#define FILE_MODE_WRITE (1 << 1) +#define FILE_MODE_APPEND (1 << 2) +#define FILE_MODE_CREATE (1 << 3) +#define FILE_MODE_TRUNCATE (1 << 4) +#define FILE_MODE_BINARY (1 << 5) +#define FILE_MODE_EXCL (1 << 6) +#define FILE_MODE_CLOEXEC (1 << 7) + #include #define fbufsize __fbufsize size_t fbufsize_unlocked(FILE* fp); @@ -251,6 +261,7 @@ int fsetdefaultbuf_unlocked(FILE* fp); int fcloseall(void); int fshutdown(FILE* fp); int fpipe(FILE* pipes[2]); +int fparsemode(const char*); #endif #if defined(_SORTIX_SOURCE) || defined(_WANT_SORTIX_VPRINTF_CALLBACK) diff --git a/libc/stdio/clearerr_unlocked.cpp b/libc/stdio/clearerr_unlocked.cpp index cf5137b9..4bce93cb 100644 --- a/libc/stdio/clearerr_unlocked.cpp +++ b/libc/stdio/clearerr_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -26,6 +26,5 @@ extern "C" void clearerr_unlocked(FILE* fp) { - if ( fp->clearerr_func ) - fp->clearerr_func(fp->user); + fp->flags &= ~_FILE_STATUS_ERROR; } diff --git a/libc/stdio/fdio.cpp b/libc/stdio/fdio.cpp index 81f8f798..11776215 100644 --- a/libc/stdio/fdio.cpp +++ b/libc/stdio/fdio.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -22,234 +22,51 @@ *******************************************************************************/ -#include - #include -#include -#include -#include -#include #include #include "fdio.h" -const int FDIO_WRITING = 1 << 0; -const int FDIO_READING = 1 << 1; -const int FDIO_APPEND = 1 << 2; -const int FDIO_ERROR = 1 << 3; -const int FDIO_EOF = 1 << 4; - -typedef struct fdio_struct -{ - int flags; - int fd; -} fdio_t; - -static int fdio_reopen(void* user, const char* mode) +int fdio_reopen(void* user, const char* mode) { (void) user; (void) mode; // TODO: Unfortunately, we don't support this yet. Note that we don't really // have to support this according to POSIX - but it'd be nicer to push this // restriction into the kernel and argue it's a security problem "What? No - // you can't make this read-only descriptor readable!". + // you can't make this read-only descriptor writable!". return errno = ENOTSUP, -1; } -static size_t fdio_read(void* ptr, size_t size, size_t nmemb, void* user) +ssize_t fdio_read(void* user, void* ptr, size_t size) { - uint8_t* buf = (uint8_t*) ptr; - fdio_t* fdio = (fdio_t*) user; - if ( !(fdio->flags & FDIO_READING) ) - return errno = EBADF, 0; - size_t sofar = 0; - size_t total = size * nmemb; - while ( sofar < total ) - { - ssize_t numbytes = read(fdio->fd, buf + sofar, total - sofar); - if ( numbytes < 0 ) { fdio->flags |= FDIO_ERROR; break; } - if ( numbytes == 0 ) { fdio->flags |= FDIO_EOF; break; } - // TODO: Is this a bug? Looks like one, but perhaps this is needed when - // reading from line-buffered terminals. - return numbytes / size; - sofar += numbytes; - } - return sofar / size; + struct fdio_state* fdio = (struct fdio_state*) user; + return read(fdio->fd, ptr, size); } -static size_t fdio_write(const void* ptr, size_t size, size_t nmemb, void* user) +ssize_t fdio_write(void* user, const void* ptr, size_t size) { - const uint8_t* buf = (const uint8_t*) ptr; - fdio_t* fdio = (fdio_t*) user; - if ( !(fdio->flags & FDIO_WRITING) ) - return errno = EBADF, 0; - size_t sofar = 0; - size_t total = size * nmemb; - while ( sofar < total ) - { - ssize_t numbytes = write(fdio->fd, buf + sofar, total - sofar); - if ( numbytes < 0 ) { fdio->flags |= FDIO_ERROR; break; } - if ( numbytes == 0 ) { fdio->flags |= FDIO_EOF; break; } - sofar += numbytes; - } - return sofar / size; + struct fdio_state* fdio = (struct fdio_state*) user; + return write(fdio->fd, ptr, size); } -static int fdio_seek(void* user, off_t offset, int whence) +off_t fdio_seek(void* user, off_t offset, int whence) { - fdio_t* fdio = (fdio_t*) user; - return 0 <= lseek(fdio->fd, offset, whence) ? 0 : -1; + struct fdio_state* fdio = (struct fdio_state*) user; + return lseek(fdio->fd, offset, whence); } -static off_t fdio_tell(void* user) +int fdio_fileno(void* user) { - fdio_t* fdio = (fdio_t*) user; - return lseek(fdio->fd, 0, SEEK_CUR);; -} - -static void fdio_seterr(void* user) -{ - fdio_t* fdio = (fdio_t*) user; - fdio->flags |= FDIO_ERROR; -} - -static void fdio_clearerr(void* user) -{ - fdio_t* fdio = (fdio_t*) user; - fdio->flags &= ~FDIO_ERROR; -} - -static int fdio_eof(void* user) -{ - fdio_t* fdio = (fdio_t*) user; - return fdio->flags & FDIO_EOF; -} - -static int fdio_error(void* user) -{ - fdio_t* fdio = (fdio_t*) user; - return fdio->flags & FDIO_ERROR; -} - -static int fdio_fileno(void* user) -{ - fdio_t* fdio = (fdio_t*) user; + struct fdio_state* fdio = (struct fdio_state*) user; return fdio->fd; } -static int fdio_close(void* user) +int fdio_close(void* user) { - fdio_t* fdio = (fdio_t*) user; + struct fdio_state* fdio = (struct fdio_state*) user; int result = close(fdio->fd); - free(fdio); + if ( fdio->free_indirect ) + fdio->free_indirect(fdio); return result; } - -extern "C" int fdio_open_descriptor(const char* path, const char* mode) -{ - int omode = 0; - int oflags = 0; - char c; - // TODO: This is too hacky and a little buggy. - const char* origmode = mode; - while ( (c = *mode++) ) - switch ( c ) - { - case 'r': omode = O_RDONLY; break; - case 'a': oflags |= O_APPEND; /* fall-through */ - case 'w': omode = O_WRONLY; oflags |= O_CREAT | O_TRUNC; break; - case '+': - omode = O_RDWR; - break; - case 'b': break; - case 't': break; - default: - fprintf(stderr, "Unsupported fopen mode: '%s'\n", origmode); - errno = EINVAL; - return -1; - } - return open(path, omode | oflags, 0666); -} - -extern "C" int fdio_install_fd(FILE* fp, int fd, const char* mode) -{ - fdio_t* fdio = (fdio_t*) calloc(1, sizeof(fdio_t)); - if ( !fdio ) - return 0; - fdio->fd = fd; - char c; - // TODO: This is too hacky and a little buggy. - while ( ( c = *mode++ ) ) - { - switch ( c ) - { - case 'r': fdio->flags |= FDIO_READING; break; - case 'w': fdio->flags |= FDIO_WRITING; break; - case '+': fdio->flags |= FDIO_READING | FDIO_WRITING; break; - case 'a': fdio->flags |= FDIO_WRITING | FDIO_APPEND; break; - case 't': break; - case 'b': break; - default: errno = EINVAL; free(fdio); return 0; - } - } - struct stat st; - if ( !fstat(fd, &st) && fdio->flags & FDIO_WRITING && S_ISDIR(st.st_mode) ) - return free(fdio), errno = EISDIR, 0; - fp->user = fdio; - fp->reopen_func = fdio_reopen; - fp->read_func = fdio_read; - fp->write_func = fdio_write; - fp->seek_func = fdio_seek; - fp->tell_func = fdio_tell; - fp->seterr_func = fdio_seterr; - fp->clearerr_func = fdio_clearerr; - fp->eof_func = fdio_eof; - fp->error_func = fdio_error; - fp->fileno_func = fdio_fileno; - fp->close_func = fdio_close; - int preserved_errno = errno; - if ( lseek(fd, 0, SEEK_CUR) < 0 && errno == ESPIPE ) - fp->flags |= _FILE_STREAM; - errno = preserved_errno; - return 1; -} - -extern "C" int fdio_install_path(FILE* fp, const char* path, const char* mode) -{ - int fd = fdio_open_descriptor(path, mode); - if ( fd < 0 ) - return 0; - if ( !fdio_install_fd(fp, fd, mode) ) - return close(fd), 0; - return 1; -} - -extern "C" FILE* fdio_new_fd(int fd, const char* mode) -{ - FILE* fp = fnewfile(); - if ( !fp ) - return NULL; - if ( !fdio_install_fd(fp, fd, mode) ) - return fclose(fp), (FILE*) NULL; - return fp; -} - -extern "C" FILE* fdio_new_path(const char* path, const char* mode) -{ - FILE* fp = fnewfile(); - if ( !fp ) - return NULL; - if ( !fdio_install_path(fp, path, mode) ) - return fclose(fp), (FILE*) NULL; - return fp; -} - -extern "C" FILE* fdopen(int fd, const char* mode) -{ - return fdio_new_fd(fd, mode); -} - -extern "C" FILE* fopen(const char* path, const char* mode) -{ - return fdio_new_path(path, mode); -} diff --git a/libc/stdio/fdio.h b/libc/stdio/fdio.h index cb511697..cea19e72 100644 --- a/libc/stdio/fdio.h +++ b/libc/stdio/fdio.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2014. This file is part of the Sortix C Library. @@ -23,17 +23,34 @@ *******************************************************************************/ #ifndef STDIO_FDIO_H -#define STDIO_FDIO_H 1 +#define STDIO_FDIO_H #include +#include + +#if !defined(__cplusplus) +#include +#endif +#include + __BEGIN_DECLS -int fdio_install_fd(FILE* fp, int fd, const char* mode); -int fdio_install_path(FILE* fp, const char* path, const char* mode); -FILE* fdio_new_fd(int fd, const char* mode); -FILE* fdio_new_path(const char* path, const char* mode); -int fdio_open_descriptor(const char* path, const char* mode); +struct fdio_state +{ + void (*free_indirect)(void*); + int fd; +}; + +int fdio_reopen(void* user, const char* mode); +ssize_t fdio_read(void* user, void* ptr, size_t size); +ssize_t fdio_write(void* user, const void* ptr, size_t size); +off_t fdio_seek(void* user, off_t offset, int whence); +int fdio_fileno(void* user); +int fdio_close(void* user); + +bool fdio_install_fd(FILE* fp, int fd, const char* mode); +bool fdio_install_path(FILE* fp, const char* path, const char* mode); __END_DECLS diff --git a/libc/stdio/fdio_install_fd.cpp b/libc/stdio/fdio_install_fd.cpp new file mode 100644 index 00000000..a5e3912c --- /dev/null +++ b/libc/stdio/fdio_install_fd.cpp @@ -0,0 +1,71 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + stdio/fdio_install_fd.cpp + Opens a FILE from a file descriptor. + +*******************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include "fdio.h" + +extern "C" bool fdio_install_fd(FILE* fp, int fd, const char* mode) +{ + int mode_flags = fparsemode(mode); + if ( mode_flags < 0 ) + return false; + + if ( !(mode_flags & (FILE_MODE_READ | FILE_MODE_WRITE)) ) + return errno = EINVAL, false; + + struct stat st; + if ( fstat(fd, &st) == 0 && + (mode_flags & FILE_MODE_WRITE) && + S_ISDIR(st.st_mode) ) + return errno = EISDIR, false; + + struct fdio_state* fdio = (struct fdio_state*) malloc(sizeof(struct fdio_state)); + if ( !fdio ) + return false; + + fdio->free_indirect = free; + fdio->fd = fd; + + if ( mode_flags & FILE_MODE_READ ) + fp->flags |= _FILE_READABLE; + if ( mode_flags & FILE_MODE_WRITE ) + fp->flags |= _FILE_WRITABLE; + + fp->user = fdio; + fp->reopen_func = fdio_reopen; + fp->read_func = fdio_read; + fp->write_func = fdio_write; + fp->seek_func = fdio_seek; + fp->fileno_func = fdio_fileno; + fp->close_func = fdio_close; + + return true; +} diff --git a/libc/stdio/fdio_install_path.cpp b/libc/stdio/fdio_install_path.cpp new file mode 100644 index 00000000..ea63a600 --- /dev/null +++ b/libc/stdio/fdio_install_path.cpp @@ -0,0 +1,58 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + stdio/fdio_install_path.cpp + Opens a FILE from a path. + +*******************************************************************************/ + +#include +#include +#include +#include + +#include "fdio.h" + +extern "C" bool fdio_install_path(FILE* fp, const char* path, const char* mode) +{ + int mode_flags = fparsemode(mode); + if ( mode_flags < 0 ) + return false; + + if ( !(mode_flags & (FILE_MODE_READ | FILE_MODE_WRITE)) ) + return errno = EINVAL, false; + + int open_flags = 0; + if ( mode_flags & FILE_MODE_READ ) open_flags |= O_READ; + if ( mode_flags & FILE_MODE_WRITE ) open_flags |= O_WRITE; + if ( mode_flags & FILE_MODE_APPEND ) open_flags |= O_APPEND; + if ( mode_flags & FILE_MODE_CREATE ) open_flags |= O_CREATE; + if ( mode_flags & FILE_MODE_TRUNCATE ) open_flags |= O_TRUNC; + if ( mode_flags & FILE_MODE_EXCL ) open_flags |= O_EXCL; + if ( mode_flags & FILE_MODE_CLOEXEC ) open_flags |= O_CLOEXEC; + + int fd = open(path, open_flags, 0666); + if ( fd < 0 ) + return false; + + if ( !fdio_install_fd(fp, fd, mode) ) + return close(fd), false; + + return true; +} diff --git a/libc/stdio/fdopen.cpp b/libc/stdio/fdopen.cpp new file mode 100644 index 00000000..305ce268 --- /dev/null +++ b/libc/stdio/fdopen.cpp @@ -0,0 +1,37 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + stdio/fdopen.cpp + Opens a FILE from a file descriptor. + +*******************************************************************************/ + +#include + +#include "fdio.h" + +extern "C" FILE* fdopen(int fd, const char* mode) +{ + FILE* fp = fnewfile(); + if ( !fp ) + return NULL; + if ( !fdio_install_fd(fp, fd, mode) ) + return fclose(fp), (FILE*) NULL; + return fp; +} diff --git a/libc/stdio/feof_unlocked.cpp b/libc/stdio/feof_unlocked.cpp index 14bd0402..a4daa10e 100644 --- a/libc/stdio/feof_unlocked.cpp +++ b/libc/stdio/feof_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -26,10 +26,5 @@ extern "C" int feof_unlocked(FILE* fp) { - size_t input_buffered = fp->amount_input_buffered - fp->offset_input_buffer; - if ( input_buffered ) - return 0; - if ( fp->eof_func ) - return fp->eof_func(fp->user); - return 0; + return fp->flags & _FILE_STATUS_EOF ? 1 : 0; } diff --git a/libc/stdio/ferror_unlocked.cpp b/libc/stdio/ferror_unlocked.cpp index d8e913ff..5195f9db 100644 --- a/libc/stdio/ferror_unlocked.cpp +++ b/libc/stdio/ferror_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -26,7 +26,5 @@ extern "C" int ferror_unlocked(FILE* fp) { - if ( fp->error_func ) - return fp->error_func(fp->user); - return 0; + return fp->flags & _FILE_STATUS_ERROR ? 1 : 0; } diff --git a/libc/stdio/fflush_stop_reading_unlocked.cpp b/libc/stdio/fflush_stop_reading_unlocked.cpp index 60828a5d..9988025a 100644 --- a/libc/stdio/fflush_stop_reading_unlocked.cpp +++ b/libc/stdio/fflush_stop_reading_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -18,41 +18,43 @@ along with the Sortix C Library. If not, see . stdio/fflush_stop_reading_unlocked.cpp - Resets the FILE to a consistent state so it is ready for writing. + Resets the FILE to a consistent state ready for writing. *******************************************************************************/ #include #include +#include +#include #include extern "C" int fflush_stop_reading_unlocked(FILE* fp) { if ( !(fp->flags & _FILE_LAST_READ) ) return 0; + + if ( !(fp->flags & _FILE_READABLE) ) + return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF; + + int saved_errno = errno; + off_t my_pos = -1; + if ( fp->seek_func ) + my_pos = fp->seek_func(fp->user, 0, SEEK_CUR); + errno = saved_errno; + int ret = 0; - size_t bufferahead = fp->amount_input_buffered - fp->offset_input_buffer; - if ( (fp->flags & _FILE_STREAM) ) + if ( 0 <= my_pos ) { - if ( bufferahead ) - /* TODO: Data loss!*/{} - } - if ( !(fp->flags & _FILE_STREAM) ) - { - off_t rewind_amount = -((off_t) bufferahead); - off_t my_pos = fp->tell_func(fp->user); - off_t expected_pos = my_pos + rewind_amount; -#if 1 - if ( fp->seek_func && fp->seek_func(fp->user, expected_pos, SEEK_SET) != 0 ) -#else - if ( fp->seek_func && fp->seek_func(fp->user, rewind_amount, SEEK_CUR) != 0 ) -#endif - ret = EOF; - off_t newpos = fp->tell_func(fp->user); - assert(ret == EOF || expected_pos == newpos); + size_t buffer_ahead = fp->amount_input_buffered - fp->offset_input_buffer; + off_t expected_pos = (uintmax_t) my_pos < (uintmax_t) buffer_ahead ? 0 : + my_pos - buffer_ahead; + if ( 0 <= my_pos && fp->seek_func(fp->user, expected_pos, SEEK_SET) < 0 ) + fp->flags |= _FILE_STATUS_ERROR, ret = EOF; } + fp->amount_input_buffered = fp->offset_input_buffer = 0; fp->flags &= ~_FILE_LAST_READ; + return ret; } diff --git a/libc/stdio/fflush_stop_writing_unlocked.cpp b/libc/stdio/fflush_stop_writing_unlocked.cpp index ff3d3fa4..c1401e2a 100644 --- a/libc/stdio/fflush_stop_writing_unlocked.cpp +++ b/libc/stdio/fflush_stop_writing_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -23,20 +23,47 @@ *******************************************************************************/ #include +#include #include extern "C" int fflush_stop_writing_unlocked(FILE* fp) { if ( !(fp->flags & _FILE_LAST_WRITE) ) return 0; + + if ( !(fp->flags & _FILE_WRITABLE) ) + return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF; + if ( !fp->write_func ) - return errno = EBADF, EOF; - size_t size = sizeof(unsigned char); + return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF; + + int result = 0; + size_t count = fp->amount_output_buffered; - int ret = 0; - if ( fp->write_func(fp->buffer, size, count, fp->user) != count ) - ret = EOF; // TODO: Set errno! + size_t sofar = 0; + while ( sofar < count ) + { + size_t request = count - sofar; + if ( (size_t) SSIZE_MAX < request ) + request = SSIZE_MAX; + ssize_t amount = fp->write_func(fp->user, fp->buffer + sofar, request); + if ( amount < 0 ) + { + fp->flags |= _FILE_STATUS_ERROR; + result = EOF; + break; + } + if ( amount == 0 ) + { + fp->flags |= _FILE_STATUS_EOF; + result = EOF; + break; + } + sofar += amount; + } + fp->amount_output_buffered = 0; fp->flags &= ~_FILE_LAST_WRITE; - return ret; + + return result; } diff --git a/libc/stdio/fflush_unlocked.cpp b/libc/stdio/fflush_unlocked.cpp index c3dd144f..a394b56f 100644 --- a/libc/stdio/fflush_unlocked.cpp +++ b/libc/stdio/fflush_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -26,11 +26,9 @@ extern "C" int fflush_unlocked(FILE* fp) { - int mode = fp->flags & (_FILE_LAST_READ | _FILE_LAST_WRITE); - if ( (mode & _FILE_LAST_READ) && fflush_stop_reading_unlocked(fp) == EOF ) + if ( (fp->flags & _FILE_LAST_READ) && fflush_stop_reading_unlocked(fp) == EOF ) return EOF; - if ( (mode & _FILE_LAST_WRITE) && fflush_stop_writing_unlocked(fp) == EOF ) + if ( (fp->flags & _FILE_LAST_WRITE) && fflush_stop_writing_unlocked(fp) == EOF ) return EOF; - fp->flags |= mode; return 0; } diff --git a/libc/stdio/fgetc_unlocked.cpp b/libc/stdio/fgetc_unlocked.cpp index b683e257..a7bdf1ca 100644 --- a/libc/stdio/fgetc_unlocked.cpp +++ b/libc/stdio/fgetc_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -23,51 +23,57 @@ *******************************************************************************/ #include +#include #include #include - -#include #include #include extern "C" int fgetc_unlocked(FILE* fp) { + if ( !(fp->flags & _FILE_READABLE) ) + return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF; + if ( !(fp->flags & _FILE_BUFFER_MODE_SET) ) if ( fsetdefaultbuf_unlocked(fp) != 0 ) - return EOF; // TODO: ferror doesn't report error! + return EOF; if ( fp->buffer_mode == _IONBF ) { unsigned char c; if ( fread_unlocked(&c, sizeof(c), 1, fp) != 1 ) return EOF; - return c; + return (int) c; } if ( !fp->read_func ) - return EOF; // TODO: ferror doesn't report error! + return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF; if ( fp->flags & _FILE_LAST_WRITE ) fflush_stop_writing_unlocked(fp); + fp->flags |= _FILE_LAST_READ; + fp->flags &= ~_FILE_STATUS_EOF; - if ( fp->offset_input_buffer < fp->amount_input_buffered ) -retry: - return fp->buffer[fp->offset_input_buffer++]; + if ( !(fp->offset_input_buffer < fp->amount_input_buffered) ) + { + assert(fp->buffer && fp->buffersize); - assert(fp->buffer && fp->buffersize); + size_t pushback = _FILE_MAX_PUSHBACK; + if ( fp->buffersize <= pushback ) + pushback = 0; + size_t count = fp->buffersize - pushback; + if ( (size_t) SSIZE_MAX < count ) + count = SSIZE_MAX; + ssize_t numread = fp->read_func(fp->user, fp->buffer + pushback, count); + if ( numread < 0 ) + return fp->flags |= _FILE_STATUS_ERROR, EOF; + if ( numread == 0 ) + return fp->flags |= _FILE_STATUS_EOF, EOF; - size_t pushback = _FILE_MAX_PUSHBACK; - if ( fp->buffersize <= pushback ) - pushback = 0; - size_t count = fp->buffersize - pushback; - size_t size = sizeof(unsigned char); - size_t numread = fp->read_func(fp->buffer + pushback, size, count, fp->user); - if ( !numread ) - return EOF; + fp->offset_input_buffer = pushback; + fp->amount_input_buffered = pushback + numread; + } - fp->offset_input_buffer = pushback; - fp->amount_input_buffered = pushback + numread; - - goto retry; + return fp->buffer[fp->offset_input_buffer++]; } diff --git a/libc/stdio/fileno_unlocked.cpp b/libc/stdio/fileno_unlocked.cpp index 04b9065b..05b7a35b 100644 --- a/libc/stdio/fileno_unlocked.cpp +++ b/libc/stdio/fileno_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -27,8 +27,7 @@ extern "C" int fileno_unlocked(FILE* fp) { - int result = fp->fileno_func ? fp->fileno_func(fp->user) : -1; - if ( result < 0 ) - errno = EBADF; - return result; + if ( !fp->fileno_func ) + return errno = EBADF, -1; + return fp->fileno_func(fp->user); } diff --git a/libc/stdio/fopen.cpp b/libc/stdio/fopen.cpp new file mode 100644 index 00000000..92c472c7 --- /dev/null +++ b/libc/stdio/fopen.cpp @@ -0,0 +1,37 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + stdio/fopen.cpp + Opens a FILE from a path. + +*******************************************************************************/ + +#include + +#include "fdio.h" + +extern "C" FILE* fopen(const char* path, const char* mode) +{ + FILE* fp = fnewfile(); + if ( !fp ) + return NULL; + if ( !fdio_install_path(fp, path, mode) ) + return fclose(fp), (FILE*) NULL; + return fp; +} diff --git a/libc/stdio/fparsemode.cpp b/libc/stdio/fparsemode.cpp new file mode 100644 index 00000000..49ff2ef7 --- /dev/null +++ b/libc/stdio/fparsemode.cpp @@ -0,0 +1,54 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2014. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + stdio/fparsemode.cpp + Parses the mode argument of functions like fopen(). + +*******************************************************************************/ + +#include +#include + +extern "C" int fparsemode(const char* mode) +{ + int result; + + switch ( *mode++ ) + { + case 'r': result = FILE_MODE_READ; break; + case 'w': result = FILE_MODE_WRITE | FILE_MODE_CREATE | FILE_MODE_TRUNCATE; break; + case 'a': result = FILE_MODE_WRITE | FILE_MODE_CREATE | FILE_MODE_APPEND; break; + default: return errno = EINVAL, -1; + }; + + while ( *mode ) + { + switch ( *mode++ ) + { + case 'b': result |= FILE_MODE_BINARY; break; + case 'e': result |= FILE_MODE_CLOEXEC; break; + case 't': result &= ~FILE_MODE_BINARY; break; + case 'x': result |= FILE_MODE_EXCL; break; + case '+': result |= FILE_MODE_READ | FILE_MODE_WRITE; break; + default: return errno = EINVAL, -1; + }; + } + + return result; +} diff --git a/libc/stdio/fputc_unlocked.cpp b/libc/stdio/fputc_unlocked.cpp index 9e7aee91..b6ea2c08 100644 --- a/libc/stdio/fputc_unlocked.cpp +++ b/libc/stdio/fputc_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -22,13 +22,17 @@ *******************************************************************************/ +#include #include extern "C" int fputc_unlocked(int c, FILE* fp) { + if ( !(fp->flags & _FILE_WRITABLE) ) + return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF; + if ( !(fp->flags & _FILE_BUFFER_MODE_SET) ) if ( fsetdefaultbuf_unlocked(fp) != 0 ) - return EOF; // TODO: ferror doesn't report error! + return EOF; if ( fp->buffer_mode == _IONBF ) { @@ -39,18 +43,27 @@ extern "C" int fputc_unlocked(int c, FILE* fp) } if ( !fp->write_func ) - return EOF; // TODO: ferror doesn't report error! + return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF; if ( fp->flags & _FILE_LAST_READ ) fflush_stop_reading_unlocked(fp); - fp->flags |= _FILE_LAST_WRITE; - if ( fp->amount_output_buffered == fp->buffersize && fflush_unlocked(fp) != 0 ) - return EOF; + fp->flags |= _FILE_LAST_WRITE; + fp->flags &= ~_FILE_STATUS_EOF; + + if ( fp->amount_output_buffered == fp->buffersize ) + { + if ( !fflush_unlocked(fp) == EOF ) + return EOF; + } fp->buffer[fp->amount_output_buffered++] = c; - if ( fp->buffer_mode == _IOLBF && c == '\n' && fflush_unlocked(fp) != 0 ) - return EOF; + + if ( fp->buffer_mode == _IOLBF && c == '\n' ) + { + if ( fflush_unlocked(fp) == EOF ) + return EOF; + } return c; } diff --git a/libc/stdio/fread_unlocked.cpp b/libc/stdio/fread_unlocked.cpp index f06b82f0..1b121721 100644 --- a/libc/stdio/fread_unlocked.cpp +++ b/libc/stdio/fread_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -22,37 +22,60 @@ *******************************************************************************/ +#include +#include #include extern "C" -size_t fread_unlocked(void* ptr, size_t size, size_t nmemb, FILE* fp) +size_t fread_unlocked(void* ptr, + size_t element_size, + size_t num_elements, + FILE* fp) { + if ( !(fp->flags & _FILE_READABLE) ) + return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF; + + unsigned char* buf = (unsigned char*) ptr; + size_t count = element_size * num_elements; + if ( fp->buffer_mode == _IONBF ) { if ( !(fp->flags & _FILE_BUFFER_MODE_SET) ) if ( fsetdefaultbuf_unlocked(fp) != 0 ) - return EOF; // TODO: ferror doesn't report error! + return EOF; if ( !fp->read_func ) - return 0; // TODO: ferror doesn't report error! + return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, 0; if ( fp->flags & _FILE_LAST_WRITE ) fflush_stop_writing_unlocked(fp); fp->flags |= _FILE_LAST_READ; - return fp->read_func(ptr, size, nmemb, fp->user); + fp->flags &= ~_FILE_STATUS_EOF; + size_t sofar = 0; + while ( sofar < count ) + { + size_t request = count - sofar; + if ( (size_t) SSIZE_MAX < request ) + request = SSIZE_MAX; + ssize_t amount = fp->read_func(fp->user, buf + sofar, request); + if ( amount < 0 ) + return fp->flags |= _FILE_STATUS_ERROR, sofar / num_elements; + if ( amount == 0 ) + return fp->flags |= _FILE_STATUS_EOF, sofar / num_elements; + sofar += amount; + } + return sofar / element_size; } - unsigned char* buf = (unsigned char*) ptr; - for ( size_t n = 0; n < nmemb; n++ ) + for ( size_t n = 0; n < num_elements; n++ ) { - size_t offset = n * size; - for ( size_t i = 0; i < size; i++ ) + size_t offset = n * element_size; + for ( size_t i = 0; i < element_size; i++ ) { int c = fgetc_unlocked(fp); if ( c == EOF ) return n; - size_t index = i + offset; - buf[index] = c; + buf[offset + i] = (unsigned char) c; } } - return nmemb; + return num_elements; } diff --git a/libc/stdio/freadable_unlocked.cpp b/libc/stdio/freadable_unlocked.cpp index 17491e6f..3f6963be 100644 --- a/libc/stdio/freadable_unlocked.cpp +++ b/libc/stdio/freadable_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -26,5 +26,5 @@ extern "C" int freadable_unlocked(FILE* fp) { - return fp->read_func != NULL; + return fp->flags & _FILE_READABLE; } diff --git a/libc/stdio/freading_unlocked.cpp b/libc/stdio/freading_unlocked.cpp index 185a0192..19b54b94 100644 --- a/libc/stdio/freading_unlocked.cpp +++ b/libc/stdio/freading_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -26,9 +26,9 @@ extern "C" int freading_unlocked(FILE* fp) { - if ( fp->read_func ) - return 1; if ( fp->flags & _FILE_LAST_READ ) return 1; + if ( (fp->flags & _FILE_READABLE) && !(fp->flags & _FILE_WRITABLE) ) + return 1; return 0; } diff --git a/libc/stdio/freopen.cpp b/libc/stdio/freopen.cpp index b6967288..c8db23d7 100644 --- a/libc/stdio/freopen.cpp +++ b/libc/stdio/freopen.cpp @@ -47,7 +47,7 @@ extern "C" FILE* freopen(const char* path, const char* mode, FILE* fp) fshutdown(fp); // Attempt to open the new path and install that into our FILE object. - if ( fdio_install_path(fp, path, mode) != 0 ) + if ( !fdio_install_path(fp, path, mode) ) { fclose(fp); return NULL; diff --git a/libc/stdio/fseeko_unlocked.cpp b/libc/stdio/fseeko_unlocked.cpp index 52e483e4..0be5a706 100644 --- a/libc/stdio/fseeko_unlocked.cpp +++ b/libc/stdio/fseeko_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -27,10 +27,12 @@ extern "C" int fseeko_unlocked(FILE* fp, off_t offset, int whence) { - if ( fflush_unlocked(fp) != 0 ) - return -1; if ( !fp->seek_func ) return errno = EBADF, -1; - int ret = fp->seek_func(fp->user, offset, whence); - return ret; + if ( fflush_unlocked(fp) != 0 ) + return -1; + if ( fp->seek_func(fp->user, offset, whence) < 0 ) + return -1; + fp->flags &= ~_FILE_STATUS_EOF; + return 0; } diff --git a/libc/stdio/fsetdefaultbuf_unlocked.cpp b/libc/stdio/fsetdefaultbuf_unlocked.cpp index b15909a7..8598c188 100644 --- a/libc/stdio/fsetdefaultbuf_unlocked.cpp +++ b/libc/stdio/fsetdefaultbuf_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2013. + Copyright(C) Jonas 'Sortie' Termansen 2013, 2014. This file is part of the Sortix C Library. @@ -22,6 +22,7 @@ *******************************************************************************/ +#include #include #include #include @@ -47,21 +48,23 @@ extern "C" int fsetdefaultbuf_unlocked(FILE* fp) // Determine the buffering semantics depending on whether the destination is // an interactive device or not. -#if defined(__is_sortix_kernel) - int mode = _IOLBF; // TODO: Detect this? -#else - int mode = fp->buffer_mode != -1 ? fp->buffer_mode - : isatty(fileno_unlocked(fp)) ? _IOLBF - : _IOFBF; -#endif - int ret = setvbuf_unlocked(fp, buf, mode, BUFSIZ); - if ( ret ) + int mode = fp->buffer_mode; + if ( mode == -1 ) { - free(buf); - return -1; +#if defined(__is_sortix_kernel) + mode = _IOLBF; +#else + mode = _IOFBF; + int saved_errno = errno; + if ( isatty(fileno_unlocked(fp)) ) + mode = _IOLBF; + errno = saved_errno; +#endif } + if ( setvbuf_unlocked(fp, buf, mode, BUFSIZ) ) + return fp->flags |= _FILE_STATUS_ERROR, free(buf), -1; // The buffer now belongs to the FILE. fp->flags |= _FILE_BUFFER_OWNED; - return ret; + return 0; } diff --git a/libc/stdio/fseterr_unlocked.cpp b/libc/stdio/fseterr_unlocked.cpp index dde3e6c8..717905a0 100644 --- a/libc/stdio/fseterr_unlocked.cpp +++ b/libc/stdio/fseterr_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -26,6 +26,5 @@ extern "C" void fseterr_unlocked(FILE* fp) { - if ( fp->seterr_func ) - fp->seterr_func(fp->user); + fp->flags |= _FILE_STATUS_ERROR; } diff --git a/libc/stdio/ftello_unlocked.cpp b/libc/stdio/ftello_unlocked.cpp index 867e2b1a..d922b136 100644 --- a/libc/stdio/ftello_unlocked.cpp +++ b/libc/stdio/ftello_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -29,15 +29,14 @@ extern "C" off_t ftello_unlocked(FILE* fp) { - if ( !fp->tell_func ) - return errno = EBADF, -1; - off_t offset = fp->tell_func(fp->user); + if ( !fp->seek_func ) + return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, -1; + off_t offset = fp->seek_func(fp->user, 0, SEEK_CUR); if ( offset < 0 ) return -1; - off_t readahead = fp->amount_input_buffered - fp->offset_input_buffer; - off_t writebehind = fp->amount_output_buffered; - off_t result = offset - readahead + writebehind; - if ( result < 0 ) // Too much ungetc'ing. + off_t read_ahead = fp->amount_input_buffered - fp->offset_input_buffer; + off_t write_behind = fp->amount_output_buffered; + if ( offset < read_ahead + write_behind ) // Too much ungetc'ing. return 0; - return result; + return offset - read_ahead + write_behind; } diff --git a/libc/stdio/fwritable_unlocked.cpp b/libc/stdio/fwritable_unlocked.cpp index ade049c5..2db8b94a 100644 --- a/libc/stdio/fwritable_unlocked.cpp +++ b/libc/stdio/fwritable_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -26,5 +26,5 @@ extern "C" int fwritable_unlocked(FILE* fp) { - return fp->write_func != NULL; + return fp->flags & _FILE_WRITABLE; } diff --git a/libc/stdio/fwrite_unlocked.cpp b/libc/stdio/fwrite_unlocked.cpp index d6ccaf1b..8c7477a2 100644 --- a/libc/stdio/fwrite_unlocked.cpp +++ b/libc/stdio/fwrite_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -22,30 +22,53 @@ *******************************************************************************/ +#include +#include #include extern "C" -size_t fwrite_unlocked(const void* ptr, size_t size, size_t nmemb, FILE* fp) +size_t fwrite_unlocked(const void* ptr, + size_t element_size, + size_t num_elements, + FILE* fp) { + if ( !(fp->flags & _FILE_WRITABLE) ) + return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, -1; + + const unsigned char* buf = (const unsigned char*) ptr; + size_t count = element_size * num_elements; + if ( fp->buffer_mode == _IONBF ) { if ( !(fp->flags & _FILE_BUFFER_MODE_SET) ) if ( fsetdefaultbuf_unlocked(fp) != 0 ) - return EOF; // TODO: ferror doesn't report error! - + return EOF; if ( !fp->write_func ) - return 0; // TODO: ferror doesn't report error! + return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, 0; if ( fp->flags & _FILE_LAST_READ ) fflush_stop_reading_unlocked(fp); fp->flags |= _FILE_LAST_WRITE; - return fp->write_func(ptr, size, nmemb, fp->user); + fp->flags &= ~_FILE_STATUS_EOF; + size_t sofar = 0; + while ( sofar < count ) + { + size_t request = count - sofar; + if ( (size_t) SSIZE_MAX < request ) + request = SSIZE_MAX; + ssize_t amount = fp->write_func(fp->user, buf + sofar, request); + if ( amount < 0 ) + return fp->flags |= _FILE_STATUS_ERROR, sofar / num_elements; + if ( amount == 0 ) + return fp->flags |= _FILE_STATUS_EOF, sofar / num_elements; + sofar += amount; + } + return sofar / element_size; } - const unsigned char* buf = (const unsigned char*) ptr; - for ( size_t n = 0; n < nmemb; n++ ) + for ( size_t n = 0; n < num_elements; n++ ) { - size_t offset = n * size; - for ( size_t i = 0; i < size; i++ ) + size_t offset = n * element_size; + for ( size_t i = 0; i < element_size; i++ ) { size_t index = offset + i; if ( fputc_unlocked(buf[index], fp) == EOF ) @@ -53,5 +76,5 @@ size_t fwrite_unlocked(const void* ptr, size_t size, size_t nmemb, FILE* fp) } } - return nmemb; + return num_elements; } diff --git a/libc/stdio/fwriting_unlocked.cpp b/libc/stdio/fwriting_unlocked.cpp index b8085eb1..8ad911a7 100644 --- a/libc/stdio/fwriting_unlocked.cpp +++ b/libc/stdio/fwriting_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -26,9 +26,9 @@ extern "C" int fwriting_unlocked(FILE* fp) { - if ( fp->write_func ) - return 1; if ( fp->flags & _FILE_LAST_WRITE ) return 1; + if ( (fp->flags & _FILE_WRITABLE) && !(fp->flags & _FILE_READABLE) ) + return 1; return 0; } diff --git a/libc/stdio/getchar.cpp b/libc/stdio/getchar.cpp new file mode 100644 index 00000000..ee70a13f --- /dev/null +++ b/libc/stdio/getchar.cpp @@ -0,0 +1,33 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2011, 2014. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + stdio/getchar.cpp + Reads a character from stdin. + +*******************************************************************************/ + +#include + +extern "C" int getchar(void) +{ + flockfile(stdin); + int ret = getchar_unlocked(); + funlockfile(stdin); + return ret; +} diff --git a/libc/stdio/getchar_unlocked.cpp b/libc/stdio/getchar_unlocked.cpp new file mode 100644 index 00000000..2c0a1747 --- /dev/null +++ b/libc/stdio/getchar_unlocked.cpp @@ -0,0 +1,30 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2011, 2014. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + stdio/getchar_unlocked.cpp + Reads a character from stdin. + +*******************************************************************************/ + +#include + +extern "C" int getchar_unlocked(void) +{ + return fgetc_unlocked(stdin); +} diff --git a/libc/stdio/popen.cpp b/libc/stdio/popen.cpp index 1b8f0596..5ba01fa8 100644 --- a/libc/stdio/popen.cpp +++ b/libc/stdio/popen.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2013. + Copyright(C) Jonas 'Sortie' Termansen 2013, 2014. This file is part of the Sortix C Library. @@ -32,12 +32,6 @@ #include #include -const int POPEN_WRITING = 1 << 0; -const int POPEN_READING = 1 << 1; -const int POPEN_CLOEXEC = 1 << 2; -const int POPEN_ERROR = 1 << 3; -const int POPEN_EOF = 1 << 4; - typedef struct popen_struct { int flags; @@ -45,77 +39,23 @@ typedef struct popen_struct pid_t pid; } popen_t; -static size_t popen_read(void* ptr, size_t size, size_t nmemb, void* user) +static ssize_t popen_read(void* user, void* ptr, size_t size) { - uint8_t* buf = (uint8_t*) ptr; popen_t* info = (popen_t*) user; - if ( !(info->flags & POPEN_READING) ) - return errno = EBADF, 0; - size_t sofar = 0; - size_t total = size * nmemb; - while ( sofar < total ) - { - ssize_t numbytes = read(info->fd, buf + sofar, total - sofar); - if ( numbytes < 0 ) { info->flags |= POPEN_ERROR; break; } - if ( numbytes == 0 ) { info->flags |= POPEN_EOF; break; } - return numbytes / size; - sofar += numbytes; - } - return sofar / size; + return read(info->fd, ptr, size); } -static size_t popen_write(const void* ptr, size_t size, size_t nmemb, void* user) +static ssize_t popen_write(void* user, const void* ptr, size_t size) { - const uint8_t* buf = (const uint8_t*) ptr; popen_t* info = (popen_t*) user; - if ( !(info->flags & POPEN_WRITING) ) - return errno = EBADF, 0; - size_t sofar = 0; - size_t total = size * nmemb; - while ( sofar < total ) - { - ssize_t numbytes = write(info->fd, buf + sofar, total - sofar); - if ( numbytes < 0 ) { info->flags |= POPEN_ERROR; break; } - if ( numbytes == 0 ) { info->flags |= POPEN_EOF; break; } - sofar += numbytes; - } - return sofar / size; + return write(info->fd, ptr, size); } -static int popen_seek(void* /*user*/, off_t /*offset*/, int /*whence*/) +static off_t popen_seek(void* /*user*/, off_t /*offset*/, int /*whence*/) { return errno = ESPIPE, -1; } -static off_t popen_tell(void* /*user*/) -{ - return errno = ESPIPE, -1; -} - -static void popen_seterr(void* user) -{ - popen_t* info = (popen_t*) user; - info->flags |= POPEN_ERROR; -} - -static void popen_clearerr(void* user) -{ - popen_t* info = (popen_t*) user; - info->flags &= ~POPEN_ERROR; -} - -static int popen_eof(void* user) -{ - popen_t* info = (popen_t*) user; - return info->flags & POPEN_EOF; -} - -static int popen_error(void* user) -{ - popen_t* info = (popen_t*) user; - return info->flags & POPEN_ERROR; -} - static int popen_fileno(void* user) { popen_t* info = (popen_t*) user; @@ -125,9 +65,9 @@ static int popen_fileno(void* user) static int popen_close(void* user) { popen_t* info = (popen_t*) user; - if ( close(info->fd) ) + if ( close(info->fd) < 0 ) { - /* TODO: Should this return value be discarded? */; + // TODO: Should this return value be discarded? } int status; if ( waitpid(info->pid, &status, 0) < 0 ) @@ -136,50 +76,37 @@ static int popen_close(void* user) return status; } -static int parse_popen_type(const char* type) -{ - int ret = 0; - switch ( *type++ ) - { - case 'r': ret = POPEN_READING; break; - case 'w': ret = POPEN_WRITING; break; - default: return errno = -EINVAL, -1; - } - while ( char c = *type++ ) - switch ( c ) - { - case 'e': ret |= POPEN_CLOEXEC; break; - default: return errno = -EINVAL, -1; - } - return ret; -} - void popen_install(FILE* fp, popen_t* info) { fp->user = info; fp->read_func = popen_read; fp->write_func = popen_write; fp->seek_func = popen_seek; - fp->tell_func = popen_tell; - fp->seterr_func = popen_seterr; - fp->clearerr_func = popen_clearerr; - fp->eof_func = popen_eof; - fp->error_func = popen_error; fp->fileno_func = popen_fileno; fp->close_func = popen_close; - fp->flags |= _FILE_STREAM; } extern "C" FILE* popen(const char* command, const char* type) { - int flags, used_end, unused_end, redirect_what; + int mode_flags = fparsemode(type); + if ( mode_flags < 0 ) + return (FILE*) NULL; + + if ( mode_flags & ~(FILE_MODE_READ | FILE_MODE_WRITE | FILE_MODE_CLOEXEC | + FILE_MODE_CREATE | FILE_MODE_BINARY | FILE_MODE_TRUNCATE) ) + return errno = EINVAL, (FILE*) NULL; + + bool reading = mode_flags & FILE_MODE_READ; + bool writing = mode_flags & FILE_MODE_WRITE; + if ( reading == writing ) + return errno = EINVAL, (FILE*) NULL; + + int used_end, unused_end, redirect_what; int pipefds[2]; popen_t* info; FILE* fp; pid_t childpid; - if ( (flags = parse_popen_type(type)) < 0 ) - goto cleanup_out; if ( !(info = (popen_t*) calloc(1, sizeof(popen_t))) ) goto cleanup_out; if ( !(fp = fnewfile()) ) @@ -191,21 +118,21 @@ extern "C" FILE* popen(const char* command, const char* type) if ( childpid ) { - used_end = flags & POPEN_WRITING ? 1 /*writing*/ : 0 /*reading*/; - unused_end = flags & POPEN_WRITING ? 0 /*reading*/ : 1 /*writing*/; + used_end = writing ? 1 /*writing*/ : 0 /*reading*/; + unused_end = writing ? 0 /*reading*/ : 1 /*writing*/; close(pipefds[unused_end]); - if ( flags & POPEN_CLOEXEC ) + if ( mode_flags & FILE_MODE_CLOEXEC ) fcntl(pipefds[used_end], F_SETFL, FD_CLOEXEC); info->fd = pipefds[used_end]; - info->flags = flags; info->pid = childpid; popen_install(fp, info); + fp->flags |= writing ? _FILE_WRITABLE : _FILE_READABLE; return fp; } - redirect_what = flags & POPEN_WRITING ? 0 /*stdin*/ : 1 /*stdout*/; - used_end = flags & POPEN_WRITING ? 0 /*reading*/ : 1 /*writing*/; - unused_end = flags & POPEN_WRITING ? 1 /*writing*/ : 0 /*reading*/; + redirect_what = writing ? 0 /*stdin*/ : 1 /*stdout*/; + used_end = writing ? 0 /*reading*/ : 1 /*writing*/; + unused_end = writing ? 1 /*writing*/ : 0 /*reading*/; if ( dup2(pipefds[used_end], redirect_what) < 0 || close(pipefds[used_end]) || close(pipefds[unused_end]) ) diff --git a/libc/stdio/putchar.cpp b/libc/stdio/putchar.cpp new file mode 100644 index 00000000..bbdd4353 --- /dev/null +++ b/libc/stdio/putchar.cpp @@ -0,0 +1,33 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2011, 2014. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + stdio/putchar.cpp + Writes a character to stdout. + +*******************************************************************************/ + +#include + +extern "C" int putchar(int c) +{ + flockfile(stdin); + int ret = putchar_unlocked(c); + funlockfile(stdin); + return ret; +} diff --git a/libc/stdio/putchar_unlocked.cpp b/libc/stdio/putchar_unlocked.cpp new file mode 100644 index 00000000..9286cc50 --- /dev/null +++ b/libc/stdio/putchar_unlocked.cpp @@ -0,0 +1,30 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2011, 2014. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + stdio/putchar_unlocked.cpp + Writes a character to stdout. + +*******************************************************************************/ + +#include + +extern "C" int putchar_unlocked(int c) +{ + return fputc_unlocked(c, stdout); +} diff --git a/libc/stdio/puts.cpp b/libc/stdio/puts.cpp new file mode 100644 index 00000000..84f9b6a1 --- /dev/null +++ b/libc/stdio/puts.cpp @@ -0,0 +1,30 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2011, 2014. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + stdio/puts.cpp + Write a string and newline to stdout. + +*******************************************************************************/ + +#include + +extern "C" int puts(const char* str) +{ + return printf("%s\n", str) < 0 ? EOF : 1; +} diff --git a/libc/stdio/setvbuf_unlocked.cpp b/libc/stdio/setvbuf_unlocked.cpp index 63832905..a5cea6b6 100644 --- a/libc/stdio/setvbuf_unlocked.cpp +++ b/libc/stdio/setvbuf_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2013. + Copyright(C) Jonas 'Sortie' Termansen 2013, 2014. This file is part of the Sortix C Library. @@ -28,7 +28,7 @@ extern "C" int setvbuf_unlocked(FILE* fp, char* buf, int mode, size_t size) { if ( fp->flags & _FILE_BUFFER_MODE_SET ) - return errno = EINVAL, -1; + return fp->flags |= _FILE_STATUS_ERROR, errno = EINVAL, -1; fp->buffer_mode = mode; if ( buf ) { diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp index 7b49c43c..6edff655 100644 --- a/libc/stdio/stdio.cpp +++ b/libc/stdio/stdio.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2014. This file is part of the Sortix C Library. @@ -22,57 +22,45 @@ *******************************************************************************/ -#define __SORTIX_STDLIB_REDIRECTS 0 - #include #include -#include -#include +#include #include "fdio.h" -extern "C" { FILE* stdin; } -extern "C" { FILE* stdout; } -extern "C" { FILE* stderr; } +static struct fdio_state stdin_fdio = { NULL, 0 }; +static struct fdio_state stdout_fdio = { NULL, 1 }; +static struct fdio_state stderr_fdio = { NULL, 2 }; + +static FILE stdin_file; +static FILE stdout_file; +static FILE stderr_file; + +extern "C" { FILE* stdin = &stdin_file; } +extern "C" { FILE* stdout = &stdout_file; } +extern "C" { FILE* stderr = &stderr_file; } + +static void bootstrap_stdio(FILE* fp, struct fdio_state* fdio, int file_flags) +{ + fresetfile(fp); + + fp->flags |= file_flags; + fp->user = fdio; + fp->reopen_func = fdio_reopen; + fp->read_func = fdio_read; + fp->write_func = fdio_write; + fp->seek_func = fdio_seek; + fp->fileno_func = fdio_fileno; + fp->close_func = fdio_close; + + fregister(fp); +} extern "C" void init_stdio() { - // TODO: These calls require memory allocation and can fail - which we don't - // currently handle. How about declaring these as global objects and - // using fdio_install_fd instead? - stdin = fdio_new_fd(0, "r"); - stdout = fdio_new_fd(1, "w"); - stderr = fdio_new_fd(2, "w"); - setvbuf(stderr, NULL, _IONBF, 0); -} + bootstrap_stdio(stdin, &stdin_fdio, _FILE_READABLE); + bootstrap_stdio(stdout, &stdout_fdio, _FILE_WRITABLE); + bootstrap_stdio(stderr, &stderr_fdio, _FILE_WRITABLE); -extern "C" int getchar_unlocked(void) -{ - return fgetc_unlocked(stdin); -} - -extern "C" int putchar_unlocked(int c) -{ - return fputc_unlocked(c, stdout); -} - -extern "C" int getchar(void) -{ - flockfile(stdin); - int ret = getchar_unlocked(); - funlockfile(stdin); - return ret; -} - -extern "C" int putchar(int c) -{ - flockfile(stdin); - int ret = putchar_unlocked(c); - funlockfile(stdin); - return ret; -} - -extern "C" int puts(const char* str) -{ - return printf("%s\n", str) < 0 ? EOF : 1; + stderr->buffer_mode = _IONBF; } diff --git a/libc/stdio/ungetc_unlocked.cpp b/libc/stdio/ungetc_unlocked.cpp index 3615d900..8c221782 100644 --- a/libc/stdio/ungetc_unlocked.cpp +++ b/libc/stdio/ungetc_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -29,17 +29,28 @@ extern "C" int ungetc_unlocked(int c, FILE* fp) { + if ( !(fp->flags & _FILE_READABLE) ) + return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF; + if ( !(fp->flags & _FILE_BUFFER_MODE_SET) ) if ( fsetdefaultbuf_unlocked(fp) != 0 ) - return EOF; // TODO: ferror doesn't report error! - - if ( !fp->read_func || fp->buffer_mode == _IONBF ) - return EOF; + return EOF; if ( fp->flags & _FILE_LAST_WRITE ) fflush_stop_writing_unlocked(fp); + fp->flags |= _FILE_LAST_READ; + if ( c == EOF ) + { + fp->flags &= ~_FILE_STATUS_EOF; + return EOF; + } + + // TODO: Is this a bug that ungetc doesn't work for unbuffered files? + if ( fp->buffer_mode == _IONBF ) + return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF; + if ( fp->offset_input_buffer == 0 ) { size_t amount = fp->amount_input_buffered - fp->offset_input_buffer; @@ -52,5 +63,8 @@ extern "C" int ungetc_unlocked(int c, FILE* fp) } fp->buffer[--fp->offset_input_buffer] = c; + + fp->flags &= ~_FILE_STATUS_EOF; + return c; } diff --git a/libc/stdio/vfprintf_unlocked.cpp b/libc/stdio/vfprintf_unlocked.cpp index 410c2b9b..8e91d83f 100644 --- a/libc/stdio/vfprintf_unlocked.cpp +++ b/libc/stdio/vfprintf_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -22,18 +22,22 @@ *******************************************************************************/ +#include #include #include #include static size_t FileWriteCallback(void* user, const char* string, size_t stringlen) { - return fwrite_unlocked(string, sizeof(char), stringlen, (FILE*) user); + return fwrite_unlocked(string, 1, stringlen, (FILE*) user); } extern "C" int vfprintf_unlocked(FILE* fp, const char* restrict format, va_list list) { + if ( !(fp->flags & _FILE_WRITABLE) ) + return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF; + size_t result = vprintf_callback(FileWriteCallback, fp, format, list); if ( result == SIZE_MAX ) return -1; diff --git a/libc/stdio/vfscanf_unlocked.cpp b/libc/stdio/vfscanf_unlocked.cpp index bd238553..d91119d0 100644 --- a/libc/stdio/vfscanf_unlocked.cpp +++ b/libc/stdio/vfscanf_unlocked.cpp @@ -22,6 +22,7 @@ *******************************************************************************/ +#include #include static int wrap_fgetc(void* fp) @@ -36,5 +37,8 @@ static int wrap_ungetc(int c, void* fp) extern "C" int vfscanf_unlocked(FILE* fp, const char* format, va_list ap) { + if ( !(fp->flags & _FILE_READABLE) ) + return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF; + return vscanf_callback(fp, wrap_fgetc, wrap_ungetc, format, ap); }