From fdbd4ca90df978af67fc2b80d55b4e564fa28972 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Sat, 24 Dec 2011 04:08:10 +0100 Subject: [PATCH] Implemented large parts of the stdio(3), including fprintf. Made FILE an interface to various backends. This allows application writers to override the standard FILE API functions with their own backends. This is highly unportable - it'd be nice if a real standard existed for this. glibc already does something like this internally, but AFAIK you can't hook into it. Added fdopen(3), fopen(3), fregister(3), funregister(3), fread(3), fwrite(3), fseek(3), clearerr(3), ferror(3), feof(3), rewind(3), ftell(3), fflush(3), fclose(3), fileno(3), fnewline(3), fcloseall(3), memset(3), stdio(3), vfprintf(3), fprintf(3), and vprintf(3). Added a file-descriptor backend to the FILE API. fd's {0, 1, 2} are now initialized as stdin, stdout, and stderr when the standard library initializes. fcloseall(3) is now called on exit(3). decl/intn_t_.h now @include(size_t.h) instead of declaring it itself. Added . The following programs now flush stdout: cat(1), clear(1), editor(1), init(1), mxsh(1). printf(3) is now hooked up against vprintf(3), while Maxsi::PrintF remains using the system call, for now. --- libmaxsi/Makefile | 7 +- libmaxsi/c/decl/FILE.h | 31 +++- libmaxsi/c/fdio.c | 197 +++++++++++++++++++++ libmaxsi/c/fdio.h | 38 ++++ libmaxsi/c/file.c | 366 +++++++++++++-------------------------- libmaxsi/c/hsrc/stdint.h | 39 +++++ libmaxsi/c/hsrc/stdio.h | 46 ++--- libmaxsi/c/hsrc/string.h | 2 +- libmaxsi/c/stdio.c | 39 +++++ libmaxsi/decl/intn_t.h | 4 +- libmaxsi/init.cpp | 4 + libmaxsi/io.cpp | 32 +++- libmaxsi/process.cpp | 2 + utils/cat.cpp | 11 +- utils/clear.cpp | 1 + utils/editor.cpp | 15 +- utils/init.cpp | 1 + utils/mxsh.cpp | 6 +- 18 files changed, 560 insertions(+), 281 deletions(-) create mode 100644 libmaxsi/c/fdio.c create mode 100644 libmaxsi/c/fdio.h create mode 100644 libmaxsi/c/hsrc/stdint.h create mode 100644 libmaxsi/c/stdio.c diff --git a/libmaxsi/Makefile b/libmaxsi/Makefile index cfb33a9f..57e87037 100644 --- a/libmaxsi/Makefile +++ b/libmaxsi/Makefile @@ -28,7 +28,11 @@ LDFLAGS=$(CPULDFLAGS) ASFLAGS=$(CPUASFLAGS) NASMFLAGS=$(CPUNASMFLAGS) -COBJS=c/file.o +COBJS=\ +c/file.o \ +c/fdio.o \ +c/stdio.o \ + CHEADERS=\ c/h/unistd.h \ c/h/stdlib.h \ @@ -47,6 +51,7 @@ c/h/sys/types.h \ c/h/sys/wait.h \ c/h/stdio.h \ c/h/signal.h \ +c/h/stdint.h \ COMMONOBJS=c++.o memory.o heap.o string.o error.o format.o SORTIXOBJS:=$(addprefix sortix/,$(COMMONOBJS)) diff --git a/libmaxsi/c/decl/FILE.h b/libmaxsi/c/decl/FILE.h index 4b1bcee0..66c5911f 100644 --- a/libmaxsi/c/decl/FILE.h +++ b/libmaxsi/c/decl/FILE.h @@ -1,5 +1,32 @@ #ifndef _FILE_DECL #define _FILE_DECL -struct _IO_FILE; -typedef struct _IO_FILE FILE; +#define BUFSIZ 8192UL +#define _FILE_REGISTERED (1<<0) +#define _FILE_NO_BUFFER (1<<1) +typedef struct _FILE +{ + /* This is non-standard, but useful. If you allocate your own FILE and + register it with fregister, feel free to use modify the following members + to customize how it works. Do not call or use these data structures, + though, as the standard library library may do various kinds of buffering + and locale/encoding conversion. */ + size_t buffersize; + char* buffer; + void* user; + 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, long offset, int whence); + long (*tell_func)(void* user); + void (*clearerr_func)(void* user); + int (*eof_func)(void* user); + int (*error_func)(void* user); + int (*fileno_func)(void* user); + int (*close_func)(void* user); + void (*free_func)(struct _FILE* fp); + /* Application writers shouldn't use anything beyond this point. */ + struct _FILE* prev; + struct _FILE* next; + int flags; + size_t bufferused; +} FILE; #endif diff --git a/libmaxsi/c/fdio.c b/libmaxsi/c/fdio.c new file mode 100644 index 00000000..3aa0b6d0 --- /dev/null +++ b/libmaxsi/c/fdio.c @@ -0,0 +1,197 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of LibMaxsi. + + LibMaxsi 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. + + LibMaxsi 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 LibMaxsi. If not, see . + + fdio.c + Handles the file descriptor backend for the FILE* API. + +******************************************************************************/ + +#include +#include +#include +#include +#include +#include + +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 size_t fdio_read(void* ptr, size_t size, size_t nmemb, void* user) +{ + uint8_t* buf = (uint8_t*) ptr; + fdio_t* fdio = (fdio_t*) user; + if ( !(fdio->flags & FDIO_READING) ) { errno = EBADF; return 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; return sofar; } + if ( numbytes == 0 ) { fdio->flags |= FDIO_EOF; return sofar; } + sofar += numbytes; + } + return sofar; +} + +static size_t fdio_write(const void* ptr, size_t size, size_t nmemb, void* user) +{ + const uint8_t* buf = (const uint8_t*) ptr; + fdio_t* fdio = (fdio_t*) user; + if ( !(fdio->flags & FDIO_WRITING) ) { errno = EBADF; return 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; return sofar; } + sofar += numbytes; + } + return sofar; +} + +static int fdio_seek(void* user, long offset, int whence) +{ + fdio_t* fdio = (fdio_t*) user; + // TODO: lseek(2) is not implemented yet! + errno = EINVAL; + return -1; +} + +static long fdio_tell(void* user) +{ + fdio_t* fdio = (fdio_t*) user; + // TODO: lseek(2) is not implemented yet! + errno = EINVAL; + return -1; +} + +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; + return fdio->fd; +} + +static int fdio_close(void* user) +{ + fdio_t* fdio = (fdio_t*) user; + int result = close(fdio->fd); + free(fdio); + return result; +} + +int fdio_install(FILE* fp, const char* mode, int fd) +{ + 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 'b': break; + default: errno = EINVAL; free(fdio); return 0; + } + } + fp->user = fdio; + fp->read_func = fdio_read; + fp->write_func = fdio_write; + fp->seek_func = fdio_seek; + fp->tell_func = fdio_tell; + 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; + return 1; +} + +FILE* fdio_newfile(int fd, const char* mode) +{ + FILE* fp = fnewfile(); + if ( !fp ) { return NULL; } + if ( !fdio_install(fp, mode, fd) ) { fclose(fp); return NULL; } + return fp; +} + +FILE* fdopen(int fd, const char* mode) +{ + return fdio_newfile(fd, mode); +} + +FILE* fopen(const char* path, const char* mode) +{ + int omode = 0; + int oflags = 0; + char c; + // TODO: This is too hacky and a little buggy. + while ( ( c = *mode++ ) ) + { + switch ( c ) + { + case 'r': omode = O_RDONLY; break; + case 'a': oflags |= O_APPEND; /* fall-through */ + case 'w': omode = O_WRONLY; break; + case '+': + if ( omode == O_WRONLY ) { oflags |= O_CREAT | O_TRUNC; } + omode = O_RDWR; + break; + case 'b': break; + default: errno = EINVAL; return 0; + } + } + int fd = open(path, fd, 0666); + if ( fd < 0 ) { return NULL; } + FILE* fp = fdopen(fd, mode); + if ( !fp ) { close(fd); return NULL; } + return fp; +} + diff --git a/libmaxsi/c/fdio.h b/libmaxsi/c/fdio.h new file mode 100644 index 00000000..4be6bbcc --- /dev/null +++ b/libmaxsi/c/fdio.h @@ -0,0 +1,38 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of LibMaxsi. + + LibMaxsi 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. + + LibMaxsi 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 LibMaxsi. If not, see . + + fdio.h + Handles the file descriptor backend for the FILE* API. + +******************************************************************************/ + +#ifndef _FDIO_H +#define _FDIO_H 1 + +#include + +__BEGIN_DECLS + +int fdio_install(FILE* fp, const char* mode, int fd); +FILE* fdio_newfile(int fd, const char* mode); + +__END_DECLS + +#endif + diff --git a/libmaxsi/c/file.c b/libmaxsi/c/file.c index 1659a716..b7695be3 100644 --- a/libmaxsi/c/file.c +++ b/libmaxsi/c/file.c @@ -18,288 +18,168 @@ along with LibMaxsi. If not, see . file.c - Implements every related to the FILE structure. This API is not compatible - enough with LibMaxsi's design goals, so it is implemented as a layer upon - the C functions in LibMaxsi. + FILE* in libmaxsi is an interface to various implementations of the FILE* + API. This allows stuff like fmemopen, but also allows the application + programmers to provide their own backends. ******************************************************************************/ #include +#include #include #include -#include -#include -#if 0 +FILE* firstfile = NULL; -// TODO: Make a real errno system! -volatile int errno; -#define EINVAL 1 - -typedef struct +void fregister(FILE* fp) { - off_t pos; - mbstate_t state; -} _fpos_t; - -struct _IO_FILE -{ - int fd; - _fpos_t pos; -}; - -// TODO: Actually implement these stubs. - -char* fgets(char* restrict s, int n, FILE* restrict stream) -{ - return NULL; + fp->flags |= _FILE_REGISTERED; + if ( !firstfile ) { firstfile = fp; return; } + fp->next = firstfile; + firstfile->prev = fp; + firstfile = fp; } -FILE* fdopen(int fildes, const char* mode) +void funregister(FILE* fp) { - return NULL; + if ( !(fp->flags & _FILE_REGISTERED) ) { return; } + if ( !fp->prev ) { firstfile = fp->next; } + if ( fp->prev ) { fp->prev->next = fp->next; } + if ( fp->next ) { fp->next->prev = fp->prev; } + fp->flags &= ~_FILE_REGISTERED; } -FILE *fmemopen(void* restrict buf, size_t size, const char* restrict mode) +size_t fread(void* ptr, size_t size, size_t nmemb, FILE* fp) { - return NULL; + if ( !fp->read_func ) { errno = EBADF; return 0; } + return fp->read_func(ptr, size, nmemb, fp->user); } -FILE* fopen(const char* restrict filename, const char* restrict mode) +size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* fp) { - int len; - if ( mode[0] == '\0' ) { errno = EINVAL; return NULL; } else - if ( mode[1] == '\1' ) { len = 1; } else - if ( mode[2] == '\0' ) { len = 2; } - if ( mode[3] == '\0' ) { len = 3; } else { errno = EINVAL; return NULL; } - - int oflags; - - if ( len == 1 || (len == 2 && mode[1] == 'b') ) + if ( !fp->write_func ) { errno = EBADF; return 0; } + char* str = (char*) ptr; + size_t total = size * nmemb; + size_t sofar = 0; + while ( sofar < total ) { - switch ( mode[0] ) + size_t left = total - sofar; + if ( (!fp->bufferused && fp->buffersize <= left) || (fp->flags & _FILE_NO_BUFFER) ) { - case 'r': oflags = O_RDONLY; break; - case 'w': oflags = O_WRONLY | O_TRUNC | O_CREAT; break; - case 'a': oflags = O_WRONLY | O_APPEND | O_CREAT; break; - default: errno = EINVAL; return NULL; + return sofar + fp->write_func(str + sofar, 1, left, fp->user); + } + + size_t available = fp->buffersize - fp->bufferused; + size_t count = ( left < available ) ? left : available; + count = left; + for ( size_t i = 0; i < count; i++ ) + { + char c = str[sofar++]; + fp->buffer[fp->bufferused++] = c; + if ( c == '\n' ) + { + if ( fflush(fp) ) { return sofar; } + break; + } + } + + if ( fp->buffersize <= fp->bufferused ) + { + if ( fflush(fp) ) { return sofar; } } } - else if ( (len == 2 && mode[1] == '+') || (len == 3 && mode[1] == '+' && mode[1] == 'b') || (len == 3 && mode[1] == 'b' && mode[1] == '+') ) + return sofar; +} + +int fseek(FILE* fp, long offset, int whence) +{ + return (fp->seek_func) ? fp->seek_func(fp->user, offset, whence) : 0; +} + +void clearerr(FILE* fp) +{ + if ( fp->clearerr_func ) { fp->clearerr_func(fp->user); } +} + +int ferror(FILE* fp) +{ + if ( !fp->error_func ) { return 0; } + return fp->error_func(fp->user); +} + +int feof(FILE* fp) +{ + if ( !fp->eof_func ) { return 0; } + return fp->eof_func(fp->user); +} + +void rewind(FILE* fp) +{ + fseek(fp, 0L, SEEK_SET); + clearerr(fp); +} + +long ftell(FILE* fp) +{ + if ( !fp->tell_func ) { errno = EBADF; return -1; } + return fp->tell_func(fp->user); +} + +int fflush(FILE* fp) +{ + if ( !fp ) { - switch ( mode[0] ) - { - case 'r': oflags = O_RDWR; break; - case 'w': oflags = O_RDWR | O_TRUNC | O_CREAT; break; - case 'a': oflags = O_RDWR | O_APPEND | O_CREAT; break; - default: errno = EINVAL; return NULL; - } + int result = 0; + for ( fp = firstfile; fp; fp = fp->next ) { result |= fflush(fp); } + return result; } - else { errno = EINVAL; return NULL; } - - // TODO: Does anything else modify this mask? - // TODO: POSIX says this should be "S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH", - // but Linux applies this in a simple test case! - mode_t perms = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - - FILE* file = malloc(sizeof(FILE)); - - if ( file == NULL ) { return NULL; } - - int fd = open(filename, oflags, perms); - - if ( fd < 0 ) { free(file); return NULL; } - - file->fd = fd; - // TODO: set other stuff here! - - return file; -} - -FILE* freopen(const char* restrict filename, const char *restrict mode, FILE* restrict stream) -{ - return NULL; -} - -FILE* popen(const char* command, const char* mode) -{ - return NULL; -} - -FILE* tmpfile(void) -{ - return NULL; -} - -int fclose(FILE* stream) -{ - return -1; -} - -int feof(FILE* stream) -{ - return -1; -} - -int ferror(FILE* stream) -{ - return -1; -} - -int fflush(FILE* stream) -{ - return -1; -} - -int fgetc(FILE* stream) -{ - return -1; -} - -int fgetpos(FILE* restrict stream, fpos_t* restrict pos) -{ - return -1; -} - -int fileno(FILE* stream) -{ - return -1; -} - -int fprintf(FILE* restrict stream, const char* restrict format, ...) -{ - return -1; -} - -int fputc(int c, FILE* stream) -{ - return -1; -} - -int fputs(const char* restrict s, FILE* restrict stream) -{ - return -1; -} - -int fscanf(FILE* restrict stream, const char* restrict format, ... ) -{ - return -1; -} - -int fseek(FILE* stream, long offset, int whence) -{ - return -1; -} - -int fseeko(FILE* stream, off_t offset, int whence) -{ - return -1; -} - -int fsetpos(FILE* stream, const fpos_t* pos) -{ - return -1; -} - -int ftrylockfile(FILE* file) -{ - return -1; -} - -int getc(FILE* stream) -{ - return -1; -} - -int getc_unlocked(FILE* stream) -{ - return -1; -} - -int pclose(FILE* steam) -{ - return -1; -} - -int putc(int c, FILE* stream) -{ - return -1; -} - -int putc_unlocked(int c, FILE* steam) -{ - return -1; -} - -int setvbuf(FILE* restrict stream, char* restrict buf, int type, size_t size) -{ - return -1; -} - -int ungetc(int c, FILE* stream) -{ - return -1; -} - -int vfprintf(FILE* restrict stream, const char* restrict format, va_list ap) -{ - return -1; -} - -int vfscanf(FILE* restrict stream, const char* restrict format, va_list arg) -{ - return -1; -} - -int vprintf(FILE* restrict stream, const char* restrict format, va_list ap) -{ - return -1; -} - -long ftell(FILE* stream) -{ - return -1; -} - -off_t ftello(FILE* stream) -{ - return -1; -} - -size_t fread(void* restrict ptr, size_t size, size_t nitems, FILE* restrict stream) -{ + if ( !fp->write_func ) { errno = EBADF; return EOF; } + if ( !fp->bufferused ) { return 0; } + size_t written = fp->write_func(fp->buffer, 1, fp->bufferused, fp->user); + if ( written < fp->bufferused ) { return EOF; } + fp->bufferused = 0; return 0; } -size_t fwrite(const void* restrict ptr, size_t size, size_t nitems, FILE* restrict stream) +int fclose(FILE* fp) { - return 0; + int result = fflush(fp); + result |= (fp->close_func) ? fp->close_func(fp->user) : 0; + funregister(fp); + if ( fp->free_func ) { fp->free_func(fp); } + return result; } -void clearerr(FILE* stream) +int fileno(FILE* fp) { - + int result = (fp->fileno_func) ? fp->fileno_func(fp->user) : -1; + if ( result < 0 ) { errno = EBADF; } + return result; } -void flockfile(FILE* file) +static void ffreefile(FILE* fp) { - + free(fp->buffer); + free(fp); } -void funlockfile(FILE* file) +FILE* fnewfile(void) { - + FILE* fp = (FILE*) calloc(sizeof(FILE), 1); + if ( !fp ) { return NULL; } + fp->buffersize = BUFSIZ; + fp->buffer = (char*) malloc(fp->buffersize); + if ( !fp->buffer ) { free(fp); return NULL; } + fp->flags = 0; + fp->free_func = ffreefile; + fregister(fp); + return fp; } -void rewind(FILE* stream) +int fcloseall(void) { - + int result = 0; + while ( firstfile ) { result |= fclose(firstfile); } + return (result) ? EOF : 0; } -void setbuf(FILE* restrict stream, char* restrict buf) -{ - -} - -#endif - diff --git a/libmaxsi/c/hsrc/stdint.h b/libmaxsi/c/hsrc/stdint.h new file mode 100644 index 00000000..da7fce89 --- /dev/null +++ b/libmaxsi/c/hsrc/stdint.h @@ -0,0 +1,39 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of LibMaxsi. + + LibMaxsi 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. + + LibMaxsi 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 LibMaxsi. If not, see . + + stdint.h + Integer types. + +******************************************************************************/ + +/* TODO: POSIX-1.2008 compliance is only partial */ + +#ifndef _UNISTD_H +#define _UNISTD_H 1 + +#include + +__BEGIN_DECLS + +@include(intn_t.h) + +__END_DECLS + +#endif + diff --git a/libmaxsi/c/hsrc/stdio.h b/libmaxsi/c/hsrc/stdio.h index 25aa0a45..44a65016 100644 --- a/libmaxsi/c/hsrc/stdio.h +++ b/libmaxsi/c/hsrc/stdio.h @@ -29,18 +29,17 @@ __BEGIN_DECLS -@include(FILE.h) - -struct _fpos_t; -typedef struct _fpos_t fpos_t; - @include(off_t.h) @include(size_t.h) @include(ssize_t.h) @include(va_list.h) @include(NULL.h) -/* TODO: Implement BUFSIZ */ +@include(FILE.h) + +struct _fpos_t; +typedef struct _fpos_t fpos_t; + /* TODO: Implement L_ctermid */ #if __POSIX_OBSOLETE <= 200801 /* TODO: Implement L_tmpnam */ @@ -76,8 +75,22 @@ extern FILE* stderr; #define stdout stdout #define stderr stderr +extern void clearerr(FILE* stream); +extern int fclose(FILE* stream); +extern int feof(FILE* stream); +extern int ferror(FILE* stream); +extern int fflush(FILE* stream); +extern int fileno(FILE* stream); +extern int fprintf(FILE* restrict stream, const char* restrict format, ...); +extern size_t fread(void* restrict ptr, size_t size, size_t nitems, FILE* restrict stream); +extern int fseek(FILE* stream, long offset, int whence); +extern long ftell(FILE* stream); +extern size_t fwrite(const void* restrict ptr, size_t size, size_t nitems, FILE* restrict stream); extern void perror(const char* s); extern int printf(const char* restrict format, ...); +extern void rewind(FILE* stream); +extern int vfprintf(FILE* restrict stream, const char* restrict format, va_list ap); +extern int vprintf(const char* restrict format, va_list ap); /* TODO: These are not implemented in libmaxsi/sortix yet. */ #ifndef SORTIX_UNIMPLEMENTED @@ -91,18 +104,11 @@ extern FILE* open_memstream(char** bufp, size_t* sizep); extern FILE* popen(const char* command, const char* mode); extern FILE* tmpfile(void); extern int dprintf(int fildes, const char* restrict format, ...); -extern int fclose(FILE* stream); -extern int feof(FILE* stream); -extern int ferror(FILE* stream); -extern int fflush(FILE* stream); extern int fgetc(FILE* stream); extern int fgetpos(FILE* restrict stream, fpos_t* restrict pos); -extern int fileno(FILE* stream); -extern int fprintf(FILE* restrict stream, const char* restrict format, ...); extern int fputc(int c, FILE* stream); extern int fputs(const char* restrict s, FILE* restrict stream); extern int fscanf(FILE* restrict stream, const char* restrict format, ... ); -extern int fseek(FILE* stream, long offset, int whence); extern int fseeko(FILE* stream, off_t offset, int whence); extern int fsetpos(FILE* stream, const fpos_t* pos); extern int ftrylockfile(FILE* file); @@ -126,23 +132,16 @@ extern int sprintf(char* restrict s, const char* restrict format, ...); extern int sscanf(const char* restrict s, const char* restrict format, ...); extern int ungetc(int c, FILE* stream); extern int vdprintf(int fildes, const char* restrict format, va_list ap); -extern int vfprintf(FILE* restrict stream, const char* restrict format, va_list ap); extern int vfscanf(FILE* restrict stream, const char* restrict format, va_list arg); -extern int vprintf(const char* restrict format, va_list ap); extern int vscanf(const char* restrict format, va_list arg); extern int vsnprintf(char* restrict, size_t, const char* restrict, va_list); extern int vsprintf(char* restrict s, const char* restrict format, va_list ap); extern int vsscanf(const char* restrict s, const char* restrict format, va_list arg); -extern long ftell(FILE* stream); extern off_t ftello(FILE* stream); -extern size_t fread(void* restrict ptr, size_t size, size_t nitems, FILE* restrict stream); -extern size_t fwrite(const void* restrict ptr, size_t size, size_t nitems, FILE* restrict stream); extern ssize_t getdelim(char** restrict lineptr, size_t* restrict n, int delimiter, FILE* restrict stream); extern ssize_t getline(char** restrict lineptr, size_t* restrict n, FILE* restrict stream); -extern void clearerr(FILE* stream); extern void flockfile(FILE* file); extern void funlockfile(FILE* file); -extern void rewind(FILE* stream); extern void setbuf(FILE* restrict stream, char* restrict buf); #if __POSIX_OBSOLETE <= 200801 @@ -152,6 +151,13 @@ extern char* tempnam(const char* dir, const char* pfx); #endif #endif +#ifdef SORTIX_EXTENSIONS +void fregister(FILE* fp); +void funregister(FILE* fp); +FILE* fnewfile(void); +int fcloseall(void); +#endif + __END_DECLS #endif diff --git a/libmaxsi/c/hsrc/string.h b/libmaxsi/c/hsrc/string.h index 6379e953..ca773d6f 100644 --- a/libmaxsi/c/hsrc/string.h +++ b/libmaxsi/c/hsrc/string.h @@ -34,6 +34,7 @@ __BEGIN_DECLS @include(locale_t.h) void* memcpy(void* restrict, const void* restrict, size_t); +void* memset(void*, int, size_t); char* strcat(char* restrict, const char* restrict); int strcmp(const char*, const char*); char* strcpy(char* restrict, const char* restrict); @@ -47,7 +48,6 @@ void* memccpy(void* restrict, const void* restrict, int, size_t); void* memchr(const void*, int, size_t); int memcmp(const void*, const void*, size_t); void* memmove(void*, const void*, size_t); -void* memset(void*, int, size_t); char* stpcpy(char* restrict, const char* restrict); char* stpncpy(char* restrict, const char* restrict, size_t); char* strchr(const char*, int); diff --git a/libmaxsi/c/stdio.c b/libmaxsi/c/stdio.c new file mode 100644 index 00000000..bf0a9e97 --- /dev/null +++ b/libmaxsi/c/stdio.c @@ -0,0 +1,39 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of LibMaxsi. + + LibMaxsi 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. + + LibMaxsi 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 LibMaxsi. If not, see . + + stdio.c + Sets up stdin, stdout, stderr. + +******************************************************************************/ + +#include +#include +#include "fdio.h" + +FILE* stdin; +FILE* stdout; +FILE* stderr; + +int init_stdio() +{ + stdin = fdio_newfile(0, "r"); + stdout = fdio_newfile(1, "w"); + stderr = fdio_newfile(2, "w"); + return 0; +} diff --git a/libmaxsi/decl/intn_t.h b/libmaxsi/decl/intn_t.h index 7c64b024..09ac29fd 100644 --- a/libmaxsi/decl/intn_t.h +++ b/libmaxsi/decl/intn_t.h @@ -19,8 +19,8 @@ typedef __uintmax_t uintmax_t; /* Define an integer able to hold the size of the largest continious memory */ /* region and define pointer safe integer types. */ -typedef __size_t size_t; -typedef __ssize_t ssize_t; +@include(size_t.h) +@include(ssize_t.h) typedef __intptr_t intptr_t; typedef __uintptr_t uintptr_t; typedef __ptrdiff_t ptrdiff_t; diff --git a/libmaxsi/init.cpp b/libmaxsi/init.cpp index ecc7a296..958aaa88 100644 --- a/libmaxsi/init.cpp +++ b/libmaxsi/init.cpp @@ -35,6 +35,7 @@ namespace Maxsi extern "C" { char* program_invocation_name = program_invocation_name_data; } extern "C" void init_error_functions(); + extern "C" void init_stdio(); extern "C" void initialize_standard_library(int argc, char* argv[]) { @@ -51,5 +52,8 @@ namespace Maxsi // Initialize the dynamic heap. Memory::Init(); + + // Initialize stdio. + init_stdio(); } } diff --git a/libmaxsi/io.cpp b/libmaxsi/io.cpp index 8ed2eeb6..a1b5a006 100644 --- a/libmaxsi/io.cpp +++ b/libmaxsi/io.cpp @@ -33,6 +33,7 @@ #include #include #include +#include namespace Maxsi { @@ -72,11 +73,38 @@ namespace Maxsi } #ifdef LIBMAXSI_LIBC + size_t FileWriteCallback(void* user, const char* string, size_t stringlen) + { + FILE* fp = (FILE*) user; + return fwrite(string, 1, stringlen, fp); + } + + extern "C" int vfprintf(FILE* fp, const char* /*restrict*/ format, va_list list) + { + size_t result = Maxsi::Format::Virtual(FileWriteCallback, fp, format, list); + return (int) result; + } + + extern "C" int fprintf(FILE* fp, const char* /*restrict*/ format, ...) + { + va_list list; + va_start(list, format); + size_t result = vfprintf(fp, format, list); + va_end(list); + return (int) result; + } + + extern "C" int vprintf(const char* /*restrict*/ format, va_list list) + { + size_t result = vfprintf(stdout, format, list); + return (int) result; + } + extern "C" int printf(const char* /*restrict*/ format, ...) { va_list list; va_start(list, format); - size_t result = Maxsi::Format::Virtual(PrintCallback, NULL, format, list); + size_t result = vprintf(format, list); va_end(list); return (int) result; } @@ -87,7 +115,7 @@ namespace Maxsi va_list list; va_start(list, format); - size_t result = Maxsi::Format::Virtual(PrintCallback, NULL, format, list); + vprintf(format, list); va_end(list); printf(": %s\n", strerror(errnum)); diff --git a/libmaxsi/process.cpp b/libmaxsi/process.cpp index 4dd874a9..a95bda45 100644 --- a/libmaxsi/process.cpp +++ b/libmaxsi/process.cpp @@ -25,6 +25,7 @@ #include "platform.h" #include "syscall.h" #include "process.h" +#include namespace Maxsi { @@ -57,6 +58,7 @@ namespace Maxsi DUAL_FUNCTION(void, exit, Exit, (int status)) { + fcloseall(); _exit(status); } diff --git a/utils/cat.cpp b/utils/cat.cpp index 9a707846..bbbc9565 100644 --- a/utils/cat.cpp +++ b/utils/cat.cpp @@ -62,16 +62,17 @@ int main(int argc, char* argv[]) if ( codepoint == 0 ) { continue; } if ( codepoint & Maxsi::Keyboard::DEPRESSED ) { continue; } - if ( codepoint == Maxsi::Keyboard::UP ) { printf("\e[A"); continue; } - if ( codepoint == Maxsi::Keyboard::DOWN ) { printf("\e[B"); continue; } - if ( codepoint == Maxsi::Keyboard::RIGHT ) { printf("\e[C"); continue; } - if ( codepoint == Maxsi::Keyboard::LEFT ) { printf("\e[D"); continue; } - if ( codepoint == Maxsi::Keyboard::ESC ) { printf("\e["); lastwasesc = true; continue; } + if ( codepoint == Maxsi::Keyboard::UP ) { printf("\e[A"); fflush(stdout); continue; } + if ( codepoint == Maxsi::Keyboard::DOWN ) { printf("\e[B"); fflush(stdout); continue; } + if ( codepoint == Maxsi::Keyboard::RIGHT ) { printf("\e[C"); fflush(stdout); continue; } + if ( codepoint == Maxsi::Keyboard::LEFT ) { printf("\e[D"); fflush(stdout); continue; } + if ( codepoint == Maxsi::Keyboard::ESC ) { printf("\e["); fflush(stdout); lastwasesc = true; continue; } if ( lastwasesc && codepoint == '[' ) { continue; } if ( codepoint >= 0x80 ) { continue; } char msg[2]; msg[0] = codepoint; msg[1] = '\0'; printf(msg); + fflush(stdout); lastwasesc = false; } diff --git a/utils/clear.cpp b/utils/clear.cpp index 27024f5e..03679235 100644 --- a/utils/clear.cpp +++ b/utils/clear.cpp @@ -3,5 +3,6 @@ int main(int argc, char* argv[]) { printf("\e[H\e[2J"); + fflush(stdout); return 0; } diff --git a/utils/editor.cpp b/utils/editor.cpp index 65165718..20a669ba 100644 --- a/utils/editor.cpp +++ b/utils/editor.cpp @@ -40,6 +40,7 @@ using namespace Maxsi; void cursorto(unsigned x, unsigned y) { printf("\e[%u;%uH", y+1+1, x+1); + fflush(stdout); } void drawtextmode() @@ -54,6 +55,7 @@ void drawtextmode() if ( y < HEIGHT-1 ) { printf("\n"); } } + fflush(stdout); cursorto(cursorx, cursory); } @@ -125,7 +127,8 @@ unsigned textmode() buffers[cursory][x] = buffers[cursory][x+1]; bufferchanged = true; } - printf("\e[2K\r%s", buffers[cursory]); + printf("\e[2K\r%s", buffers[cursory]); + fflush(stdout); } else if ( 0 < cursory && strlen(buffers[cursory]) == 0 ) { @@ -161,6 +164,7 @@ unsigned textmode() msg[1] = 0; printf("%s", msg); buffers[cursory][cursorx++] = codepoint; + fflush(stdout); bufferchanged = true; if ( WIDTH <= cursorx ) { cursorx = WIDTH-1; } } @@ -230,6 +234,7 @@ int savemode() retry: size_t len = strlen(writefilename); printf("File Name to Write: %s", writefilename); + fflush(stdout); bool readytosave = false; @@ -247,7 +252,7 @@ retry: return MODE_TEXT; break; case '\b': - if ( 0 < len ) { printf("\b"); writefilename[--len] = 0; } + if ( 0 < len ) { printf("\b"); fflush(stdout); writefilename[--len] = 0; } break; case '\n': if ( len == 0 ) { return MODE_TEXT; } @@ -262,6 +267,7 @@ retry: msg[0] = codepoint; msg[1] = 0; printf("%s", msg); + fflush(stdout); } } @@ -327,6 +333,7 @@ int loadmode() retry: size_t len = strlen(loadfilename); printf("File Name to Load: %s", loadfilename); + fflush(stdout); bool readytoload = false; @@ -344,7 +351,7 @@ retry: return MODE_TEXT; break; case '\b': - if ( 0 < len ) { printf("\b"); loadfilename[--len] = 0; } + if ( 0 < len ) { printf("\b"); fflush(stdout); loadfilename[--len] = 0; } break; case '\n': if ( len == 0 ) { return MODE_TEXT; } @@ -359,6 +366,7 @@ retry: msg[0] = codepoint; msg[1] = 0; printf("%s", msg); + fflush(stdout); } } @@ -406,6 +414,7 @@ void run() } printf("\e[37m\e[40m\e[2J\e[H"); + fflush(stdout); } int main(int argc, char* argv[]) diff --git a/utils/init.cpp b/utils/init.cpp index d9f0b54f..e255c4ea 100644 --- a/utils/init.cpp +++ b/utils/init.cpp @@ -37,6 +37,7 @@ int main(int argc, char* argv[]) // Reset the terminal's color and the rest of it. printf("\r\e[m\e[J"); + fflush(stdout); pid_t childpid = Process::Fork(); if ( childpid < 0 ) { perror("fork"); return 2; } diff --git a/utils/mxsh.cpp b/utils/mxsh.cpp index fb503b8b..73c21025 100644 --- a/utils/mxsh.cpp +++ b/utils/mxsh.cpp @@ -22,7 +22,8 @@ void command() const char* wd = getcwd(cwd, CWD_SIZE); if ( !wd ) { wd = "?"; } - printf("root@sortix %s # ", wd); + printf("root@sortix %s # ", wd); + fflush(stdout); const size_t commandsize = 128; char command[commandsize + 1]; @@ -39,7 +40,7 @@ void command() if ( codepoint == '\b' ) { - if ( 0 < commandused ) { printf("\b"); commandused--; } + if ( 0 < commandused ) { printf("\b"); fflush(stdout); commandused--; } continue; } @@ -47,6 +48,7 @@ void command() char msg[2]; msg[0] = codepoint; msg[1] = '\0'; printf("%s", msg); + fflush(stdout); if ( codepoint == '\n' ) { command[commandused] = '\0'; break; }