mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Revise stdio implementation.
This commit is contained in:
parent
b4c38fd044
commit
d7c54161b2
41 changed files with 815 additions and 520 deletions
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
71
libc/stdio/fdio_install_fd.cpp
Normal file
71
libc/stdio/fdio_install_fd.cpp
Normal 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;
|
||||
}
|
58
libc/stdio/fdio_install_path.cpp
Normal file
58
libc/stdio/fdio_install_path.cpp
Normal 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
37
libc/stdio/fdopen.cpp
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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++];
|
||||
}
|
||||
|
|
|
@ -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
37
libc/stdio/fopen.cpp
Normal 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
54
libc/stdio/fparsemode.cpp
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
33
libc/stdio/getchar.cpp
Normal 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;
|
||||
}
|
30
libc/stdio/getchar_unlocked.cpp
Normal file
30
libc/stdio/getchar_unlocked.cpp
Normal 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);
|
||||
}
|
|
@ -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
33
libc/stdio/putchar.cpp
Normal 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;
|
||||
}
|
30
libc/stdio/putchar_unlocked.cpp
Normal file
30
libc/stdio/putchar_unlocked.cpp
Normal 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
30
libc/stdio/puts.cpp
Normal 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;
|
||||
}
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue