Rewrite stdio functions.
These changes aim to make the stdio functions much more stable, flexible, correct and bugfree.
This commit is contained in:
parent
8e0aefda20
commit
9ad7690c74
|
@ -37,6 +37,8 @@ fclose.o \
|
||||||
feof.o \
|
feof.o \
|
||||||
ferror.o \
|
ferror.o \
|
||||||
fflush.o \
|
fflush.o \
|
||||||
|
fflush_stop_reading.o \
|
||||||
|
fflush_stop_writing.o \
|
||||||
fgetc.o \
|
fgetc.o \
|
||||||
fgets.o \
|
fgets.o \
|
||||||
flbf.o \
|
flbf.o \
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#define _FILE_LAST_WRITE (1<<2)
|
#define _FILE_LAST_WRITE (1<<2)
|
||||||
#define _FILE_LAST_READ (1<<3)
|
#define _FILE_LAST_READ (1<<3)
|
||||||
#define _FILE_AUTO_LOCK (1<<4)
|
#define _FILE_AUTO_LOCK (1<<4)
|
||||||
|
#define _FILE_STREAM (1<<5)
|
||||||
#define _FILE_MAX_PUSHBACK 8
|
#define _FILE_MAX_PUSHBACK 8
|
||||||
typedef struct _FILE
|
typedef struct _FILE
|
||||||
{
|
{
|
||||||
|
@ -14,7 +15,7 @@ typedef struct _FILE
|
||||||
to customize how it works. Don't call the functions directly, though, as
|
to customize how it works. Don't call the functions directly, though, as
|
||||||
the standard library does various kinds of buffering and conversion. */
|
the standard library does various kinds of buffering and conversion. */
|
||||||
size_t buffersize;
|
size_t buffersize;
|
||||||
char* buffer;
|
unsigned char* buffer;
|
||||||
void* user;
|
void* user;
|
||||||
size_t (*read_func)(void* ptr, size_t size, size_t nmemb, 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);
|
size_t (*write_func)(const void* ptr, size_t size, size_t nmemb, void* user);
|
||||||
|
@ -31,8 +32,8 @@ typedef struct _FILE
|
||||||
struct _FILE* prev;
|
struct _FILE* prev;
|
||||||
struct _FILE* next;
|
struct _FILE* next;
|
||||||
int flags;
|
int flags;
|
||||||
size_t bufferused;
|
size_t offset_input_buffer;
|
||||||
size_t numpushedback;
|
size_t amount_input_buffered;
|
||||||
unsigned char pushedback[_FILE_MAX_PUSHBACK];
|
size_t amount_output_buffered;
|
||||||
} FILE;
|
} FILE;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -29,6 +29,7 @@ extern "C" int fclose(FILE* fp)
|
||||||
int result = fflush(fp);
|
int result = fflush(fp);
|
||||||
result |= fp->close_func ? fp->close_func(fp->user) : 0;
|
result |= fp->close_func ? fp->close_func(fp->user) : 0;
|
||||||
funregister(fp);
|
funregister(fp);
|
||||||
if ( fp->free_func ) { fp->free_func(fp); }
|
if ( fp->free_func )
|
||||||
|
fp->free_func(fp);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ static size_t fdio_read(void* ptr, size_t size, size_t nmemb, void* user)
|
||||||
ssize_t numbytes = read(fdio->fd, buf + sofar, total - sofar);
|
ssize_t numbytes = read(fdio->fd, buf + sofar, total - sofar);
|
||||||
if ( numbytes < 0 ) { fdio->flags |= FDIO_ERROR; break; }
|
if ( numbytes < 0 ) { fdio->flags |= FDIO_ERROR; break; }
|
||||||
if ( numbytes == 0 ) { fdio->flags |= FDIO_EOF; break; }
|
if ( numbytes == 0 ) { fdio->flags |= FDIO_EOF; break; }
|
||||||
|
return numbytes / size;
|
||||||
sofar += numbytes;
|
sofar += numbytes;
|
||||||
}
|
}
|
||||||
return sofar / size;
|
return sofar / size;
|
||||||
|
@ -163,6 +164,8 @@ int fdio_install(FILE* fp, const char* mode, int fd)
|
||||||
fp->error_func = fdio_error;
|
fp->error_func = fdio_error;
|
||||||
fp->fileno_func = fdio_fileno;
|
fp->fileno_func = fdio_fileno;
|
||||||
fp->close_func = fdio_close;
|
fp->close_func = fdio_close;
|
||||||
|
if ( lseek(fd, 0, SEEK_CUR) < 0 && errno == ESPIPE )
|
||||||
|
fp->flags |= _FILE_STREAM;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,8 @@
|
||||||
|
|
||||||
extern "C" int feof(FILE* fp)
|
extern "C" int feof(FILE* fp)
|
||||||
{
|
{
|
||||||
if ( fp->numpushedback )
|
size_t input_buffered = fp->amount_input_buffered - fp->offset_input_buffer;
|
||||||
|
if ( input_buffered )
|
||||||
return 0;
|
return 0;
|
||||||
if ( fp->eof_func )
|
if ( fp->eof_func )
|
||||||
return fp->eof_func(fp->user);
|
return fp->eof_func(fp->user);
|
||||||
|
|
|
@ -33,10 +33,12 @@ extern "C" int fflush(FILE* fp)
|
||||||
for ( fp = _firstfile; fp; fp = fp->next ) { result |= fflush(fp); }
|
for ( fp = _firstfile; fp; fp = fp->next ) { result |= fflush(fp); }
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if ( !fp->write_func ) { errno = EBADF; return EOF; }
|
|
||||||
if ( !fp->bufferused ) { return 0; }
|
int mode = fp->flags & (_FILE_LAST_READ | _FILE_LAST_WRITE);
|
||||||
size_t written = fp->write_func(fp->buffer, 1, fp->bufferused, fp->user);
|
if ( (mode & _FILE_LAST_READ) && fflush_stop_reading(fp) == EOF )
|
||||||
if ( written < fp->bufferused ) { return EOF; }
|
return EOF;
|
||||||
fp->bufferused = 0;
|
if ( (mode & _FILE_LAST_WRITE) && fflush_stop_writing(fp) == EOF )
|
||||||
|
return EOF;
|
||||||
|
fp->flags |= mode;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
|
||||||
|
fflush_stop_reading.cpp
|
||||||
|
Resets the FILE to a consistent state so it is ready for writing.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern "C" int fflush_stop_reading(FILE* fp)
|
||||||
|
{
|
||||||
|
if ( !(fp->flags & _FILE_LAST_READ) )
|
||||||
|
return 0;
|
||||||
|
int ret = 0;
|
||||||
|
size_t bufferahead = fp->amount_input_buffered - fp->offset_input_buffer;
|
||||||
|
if ( (fp->flags & _FILE_STREAM) )
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
fp->amount_input_buffered = fp->offset_input_buffer = 0;
|
||||||
|
fp->flags &= ~_FILE_LAST_READ;
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
|
||||||
|
fflush_stop_writing.cpp
|
||||||
|
Resets the FILE to a consistent state so it is ready for reading.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern "C" int fflush_stop_writing(FILE* fp)
|
||||||
|
{
|
||||||
|
if ( !(fp->flags & _FILE_LAST_WRITE) )
|
||||||
|
return 0;
|
||||||
|
if ( !fp->write_func )
|
||||||
|
return errno = EBADF, EOF;
|
||||||
|
size_t size = sizeof(unsigned char);
|
||||||
|
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!
|
||||||
|
fp->amount_output_buffered = 0;
|
||||||
|
fp->flags &= ~_FILE_LAST_WRITE;
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -22,11 +22,48 @@
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
extern "C" int fgetc(FILE* fp)
|
extern "C" int fgetc(FILE* fp)
|
||||||
{
|
{
|
||||||
|
if ( fp->flags & _FILE_NO_BUFFER )
|
||||||
|
{
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
if ( fread(&c, 1, sizeof(c), fp) < sizeof(c) ) { return EOF; }
|
if ( fread(&c, sizeof(c), 1, fp) != 1 )
|
||||||
|
return EOF;
|
||||||
return c;
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !fp->read_func )
|
||||||
|
return EOF; // TODO: ferror doesn't report error!
|
||||||
|
|
||||||
|
if ( fp->flags & _FILE_LAST_WRITE )
|
||||||
|
fflush_stop_writing(fp);
|
||||||
|
fp->flags |= _FILE_LAST_READ;
|
||||||
|
|
||||||
|
if ( fp->offset_input_buffer < fp->amount_input_buffered )
|
||||||
|
retry:
|
||||||
|
return fp->buffer[fp->offset_input_buffer++];
|
||||||
|
|
||||||
|
assert(fp->buffer && fp->buffersize);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,9 +36,12 @@ extern "C" FILE* fnewfile(void)
|
||||||
FILE* fp = (FILE*) calloc(sizeof(FILE), 1);
|
FILE* fp = (FILE*) calloc(sizeof(FILE), 1);
|
||||||
if ( !fp ) { return NULL; }
|
if ( !fp ) { return NULL; }
|
||||||
fp->buffersize = BUFSIZ;
|
fp->buffersize = BUFSIZ;
|
||||||
fp->buffer = (char*) malloc(fp->buffersize);
|
fp->buffer = (unsigned char*) malloc(fp->buffersize);
|
||||||
if ( !fp->buffer ) { free(fp); return NULL; }
|
if ( !fp->buffer ) { free(fp); return NULL; }
|
||||||
fp->flags = _FILE_AUTO_LOCK;
|
fp->flags = _FILE_AUTO_LOCK;
|
||||||
|
fp->offset_input_buffer = 0;
|
||||||
|
fp->amount_input_buffered = 0;
|
||||||
|
fp->amount_output_buffered = 0;
|
||||||
fp->free_func = ffreefile;
|
fp->free_func = ffreefile;
|
||||||
fregister(fp);
|
fregister(fp);
|
||||||
return fp;
|
return fp;
|
||||||
|
|
|
@ -26,5 +26,5 @@
|
||||||
|
|
||||||
extern "C" size_t fpending(FILE* fp)
|
extern "C" size_t fpending(FILE* fp)
|
||||||
{
|
{
|
||||||
return fp->bufferused;
|
return fp->amount_output_buffered;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,5 +26,7 @@
|
||||||
|
|
||||||
extern "C" void fpurge(FILE* fp)
|
extern "C" void fpurge(FILE* fp)
|
||||||
{
|
{
|
||||||
fp->bufferused = 0;
|
fp->offset_input_buffer = 0;
|
||||||
|
fp->amount_input_buffered = 0;
|
||||||
|
fp->amount_output_buffered = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,29 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
extern "C" int fputc(int cint, FILE* fp)
|
extern "C" int fputc(int c, FILE* fp)
|
||||||
{
|
{
|
||||||
unsigned char c = (unsigned char) cint;
|
if ( fp->flags & _FILE_NO_BUFFER )
|
||||||
if ( fwrite(&c, 1, sizeof(c), fp) < sizeof(c) ) { return EOF; }
|
{
|
||||||
|
unsigned char c_char = c;
|
||||||
|
if ( fwrite(&c_char, sizeof(c_char), 1, fp) != 1 )
|
||||||
|
return EOF;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !fp->write_func )
|
||||||
|
return EOF; // TODO: ferror doesn't report error!
|
||||||
|
|
||||||
|
if ( fp->flags & _FILE_LAST_READ )
|
||||||
|
fflush_stop_reading(fp);
|
||||||
|
fp->flags |= _FILE_LAST_WRITE;
|
||||||
|
|
||||||
|
if ( fp->amount_output_buffered == fp->buffersize && fflush(fp) != 0 )
|
||||||
|
return EOF;
|
||||||
|
|
||||||
|
fp->buffer[fp->amount_output_buffered++] = c;
|
||||||
|
if ( c == '\n' && fflush(fp) != 0 )
|
||||||
|
return EOF;
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,23 +23,32 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
extern "C" size_t fread(void* ptr, size_t size, size_t nmemb, FILE* fp)
|
extern "C" size_t fread(void* ptr, size_t size, size_t nmemb, FILE* fp)
|
||||||
{
|
{
|
||||||
if ( fp->numpushedback && size != 1 ) { errno = ENOSYS; return 0; }
|
if ( fp->flags & _FILE_NO_BUFFER )
|
||||||
if ( fp->numpushedback && nmemb )
|
|
||||||
{
|
{
|
||||||
unsigned char* buf = (unsigned char*) ptr;
|
if ( !fp->read_func )
|
||||||
size_t amount = nmemb < fp->numpushedback ? nmemb : fp->numpushedback;
|
return 0; // TODO: ferror doesn't report error!
|
||||||
for ( size_t i = 0; i < amount; i++ )
|
if ( fp->flags & _FILE_LAST_WRITE )
|
||||||
{
|
fflush_stop_writing(fp);
|
||||||
buf[i] = fp->pushedback[--(fp->numpushedback)];
|
fp->flags |= _FILE_LAST_READ;
|
||||||
}
|
|
||||||
if ( nmemb <= amount ) { return nmemb; }
|
|
||||||
return amount + fread(buf + amount, size, nmemb - amount, fp);
|
|
||||||
}
|
|
||||||
if ( !fp->read_func ) { errno = EBADF; return 0; }
|
|
||||||
fp->flags &= ~_FILE_LAST_WRITE; fp->flags |= _FILE_LAST_READ;
|
|
||||||
return fp->read_func(ptr, size, nmemb, fp->user);
|
return fp->read_func(ptr, size, nmemb, fp->user);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* buf = (unsigned char*) ptr;
|
||||||
|
for ( size_t n = 0; n < nmemb; n++ )
|
||||||
|
{
|
||||||
|
size_t offset = n * size;
|
||||||
|
for ( size_t i = 0; i < size; i++ )
|
||||||
|
{
|
||||||
|
int c = fgetc(fp);
|
||||||
|
if ( c == EOF )
|
||||||
|
return n;
|
||||||
|
size_t index = i + offset;
|
||||||
|
buf[index] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nmemb;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,11 +22,15 @@
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
extern "C" int fseeko(FILE* fp, off_t offset, int whence)
|
extern "C" int fseeko(FILE* fp, off_t offset, int whence)
|
||||||
{
|
{
|
||||||
fp->numpushedback = 0;
|
if ( fflush(fp) != 0 )
|
||||||
fflush(fp);
|
return -1;
|
||||||
return (fp->seek_func) ? fp->seek_func(fp->user, offset, whence) : 0;
|
if ( !fp->seek_func )
|
||||||
|
return errno = EBADF, -1;
|
||||||
|
int ret = fp->seek_func(fp->user, offset, whence);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,11 +22,22 @@
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
extern "C" off_t ftello(FILE* fp)
|
extern "C" off_t ftello(FILE* fp)
|
||||||
{
|
{
|
||||||
if ( !fp->tell_func ) { errno = EBADF; return -1; }
|
if ( !fp->tell_func )
|
||||||
return fp->tell_func(fp->user) - fp->numpushedback;
|
return errno = EBADF, -1;
|
||||||
|
off_t offset = fp->tell_func(fp->user);
|
||||||
|
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.
|
||||||
|
return 0;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,43 +22,31 @@
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
extern "C" size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* fp)
|
extern "C" size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* fp)
|
||||||
{
|
{
|
||||||
|
if ( fp->flags & _FILE_NO_BUFFER )
|
||||||
|
{
|
||||||
if ( !fp->write_func )
|
if ( !fp->write_func )
|
||||||
return errno = EBADF, 0;
|
return 0; // TODO: ferror doesn't report error!
|
||||||
fp->flags &= ~_FILE_LAST_READ; fp->flags |= _FILE_LAST_WRITE;
|
if ( fp->flags & _FILE_LAST_READ )
|
||||||
char* str = (char*) ptr;
|
fflush_stop_reading(fp);
|
||||||
size_t total = size * nmemb;
|
fp->flags |= _FILE_LAST_WRITE;
|
||||||
size_t sofar = 0;
|
return fp->write_func(ptr, size, nmemb, fp->user);
|
||||||
while ( sofar < total )
|
|
||||||
{
|
|
||||||
size_t left = total - sofar;
|
|
||||||
if ( fp->flags & _FILE_NO_BUFFER || !fp->buffersize )
|
|
||||||
{
|
|
||||||
size_t ret = sofar + fp->write_func(str + sofar, 1, left, fp->user);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t available = fp->buffersize - fp->bufferused;
|
const unsigned char* buf = (const unsigned char*) ptr;
|
||||||
if ( !available )
|
for ( size_t n = 0; n < nmemb; n++ )
|
||||||
{
|
{
|
||||||
if ( fflush(fp) == 0 ) continue;
|
size_t offset = n * size;
|
||||||
else return sofar;
|
for ( size_t i = 0; i < size; i++ )
|
||||||
|
{
|
||||||
|
size_t index = offset + i;
|
||||||
|
if ( fputc(buf[index], fp) == EOF )
|
||||||
|
return n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t count = available < left ? available : left;
|
return nmemb;
|
||||||
for ( size_t i = 0; i < count; i++ )
|
|
||||||
{
|
|
||||||
char c = str[sofar++];
|
|
||||||
fp->buffer[fp->bufferused++] = c;
|
|
||||||
assert(fp->bufferused <= fp->buffersize);
|
|
||||||
if ( c == '\n' || fp->buffersize == fp->bufferused )
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sofar;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,6 +162,8 @@ extern char* tempnam(const char* dir, const char* pfx);
|
||||||
#define fpending __fpending
|
#define fpending __fpending
|
||||||
#define flushlbf _flushlbf
|
#define flushlbf _flushlbf
|
||||||
#define fsetlocking __fsetlocking
|
#define fsetlocking __fsetlocking
|
||||||
|
int fflush_stop_reading(FILE* fp);
|
||||||
|
int fflush_stop_writing(FILE* fp);
|
||||||
void fseterr(FILE* fp);
|
void fseterr(FILE* fp);
|
||||||
void fregister(FILE* fp);
|
void fregister(FILE* fp);
|
||||||
void funregister(FILE* fp);
|
void funregister(FILE* fp);
|
||||||
|
|
|
@ -25,11 +25,28 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
extern "C" int ungetc(int c, FILE* fp)
|
extern "C" int ungetc(int c, FILE* fp)
|
||||||
{
|
{
|
||||||
if ( fp->numpushedback == _FILE_MAX_PUSHBACK ) { errno = ERANGE; return EOF; }
|
if ( !fp->read_func || (fp->flags & _FILE_NO_BUFFER) )
|
||||||
unsigned char uc = c;
|
return EOF;
|
||||||
fp->pushedback[fp->numpushedback++] = uc;
|
|
||||||
return uc;
|
if ( fp->flags & _FILE_LAST_WRITE )
|
||||||
|
fflush_stop_writing(fp);
|
||||||
|
fp->flags |= _FILE_LAST_READ;
|
||||||
|
|
||||||
|
if ( fp->offset_input_buffer == 0 )
|
||||||
|
{
|
||||||
|
size_t amount = fp->amount_input_buffered - fp->offset_input_buffer;
|
||||||
|
size_t offset = fp->buffersize - amount;
|
||||||
|
if ( !offset )
|
||||||
|
return EOF;
|
||||||
|
memmove(fp->buffer + offset, fp->buffer, sizeof(fp->buffer[0]) * amount);
|
||||||
|
fp->offset_input_buffer = offset;
|
||||||
|
fp->amount_input_buffered = offset + amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp->buffer[--fp->offset_input_buffer] = c;
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue