Revise stdio implementation.

This commit is contained in:
Jonas 'Sortie' Termansen 2014-02-27 20:57:14 +01:00
parent b4c38fd044
commit d7c54161b2
41 changed files with 815 additions and 520 deletions

View File

@ -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 \

View File

@ -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 <stddef.h>
#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);

View File

@ -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 <stdio_ext.h>
#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)

View File

@ -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;
}

View File

@ -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 <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#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);
}

View File

@ -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 <sys/cdefs.h>
#include <sys/stat.h>
#if !defined(__cplusplus)
#include <stdbool.h>
#endif
#include <stdio.h>
__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

View File

@ -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 <http://www.gnu.org/licenses/>.
stdio/fdio_install_fd.cpp
Opens a FILE from a file descriptor.
*******************************************************************************/
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#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;
}

View File

@ -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 <http://www.gnu.org/licenses/>.
stdio/fdio_install_path.cpp
Opens a FILE from a path.
*******************************************************************************/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#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;
}

37
libc/stdio/fdopen.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
stdio/fdopen.cpp
Opens a FILE from a file descriptor.
*******************************************************************************/
#include <stdio.h>
#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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 <http://www.gnu.org/licenses/>.
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 <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
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;
}

View File

@ -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 <errno.h>
#include <stdint.h>
#include <stdio.h>
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;
}

View File

@ -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;
}

View File

@ -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 <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
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++];
}

View File

@ -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);
}

37
libc/stdio/fopen.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
stdio/fopen.cpp
Opens a FILE from a path.
*******************************************************************************/
#include <stdio.h>
#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;
}

54
libc/stdio/fparsemode.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
stdio/fparsemode.cpp
Parses the mode argument of functions like fopen().
*******************************************************************************/
#include <errno.h>
#include <stdio.h>
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;
}

View File

@ -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 <errno.h>
#include <stdio.h>
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;
}

View File

@ -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 <errno.h>
#include <stdint.h>
#include <stdio.h>
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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 <errno.h>
#include <stdint.h>
#include <stdio.h>
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;
}

View File

@ -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;
}

33
libc/stdio/getchar.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
stdio/getchar.cpp
Reads a character from stdin.
*******************************************************************************/
#include <stdio.h>
extern "C" int getchar(void)
{
flockfile(stdin);
int ret = getchar_unlocked();
funlockfile(stdin);
return ret;
}

View File

@ -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 <http://www.gnu.org/licenses/>.
stdio/getchar_unlocked.cpp
Reads a character from stdin.
*******************************************************************************/
#include <stdio.h>
extern "C" int getchar_unlocked(void)
{
return fgetc_unlocked(stdin);
}

View File

@ -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 <stdint.h>
#include <unistd.h>
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]) )

33
libc/stdio/putchar.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
stdio/putchar.cpp
Writes a character to stdout.
*******************************************************************************/
#include <stdio.h>
extern "C" int putchar(int c)
{
flockfile(stdin);
int ret = putchar_unlocked(c);
funlockfile(stdin);
return ret;
}

View File

@ -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 <http://www.gnu.org/licenses/>.
stdio/putchar_unlocked.cpp
Writes a character to stdout.
*******************************************************************************/
#include <stdio.h>
extern "C" int putchar_unlocked(int c)
{
return fputc_unlocked(c, stdout);
}

30
libc/stdio/puts.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
stdio/puts.cpp
Write a string and newline to stdout.
*******************************************************************************/
#include <stdio.h>
extern "C" int puts(const char* str)
{
return printf("%s\n", str) < 0 ? EOF : 1;
}

View File

@ -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 )
{

View File

@ -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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#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;
}

View File

@ -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;
}

View File

@ -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 <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
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;

View File

@ -22,6 +22,7 @@
*******************************************************************************/
#include <errno.h>
#include <stdio.h>
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);
}