fxlibc/src/libc/stdio/fileutil.c

189 lines
3.3 KiB
C

#include "fileutil.h"
#include <gint/defs/util.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int __fp_open(FILE *fp, int fd, bool use_buffering)
{
/* We initialize fdpos to 0 even in append mode (7.19.3§1) */
fp->fd = fd;
fp->fdpos = 0;
/* We assume all files in the filesystem are non-interactive in order
to conform to (7.19.5.3§7)
TODO: Vhex might want something more elaborate here */
if(use_buffering && setvbuf(fp, NULL, _IOFBF, BUFSIZ))
return -1;
return 0;
}
void __fp_close(FILE *fp, bool free_fp)
{
if(!fp)
return;
if(fp->fd >= 0) {
fflush(fp);
close(fp->fd);
}
if(fp->bufowned)
free(fp->buf);
if(free_fp)
free(fp);
}
void __fp_remove_buffer(FILE *fp)
{
if(fp->bufowned)
free(fp->buf);
fp->buf = NULL;
fp->bufowned = false;
fp->bufsize = 0;
}
bool __fp_set_buffer(FILE *fp, void *buf, size_t size)
{
bool owned = false;
if(!buf) {
owned = true;
buf = malloc(size);
if(!buf)
return false;
}
fp->buf = buf;
fp->bufowned = owned;
fp->bufsize = size;
return true;
}
void __fp_buffer_mode_read(FILE *fp)
{
if(__fp_hasbuf_write(fp)) {
fflush(fp);
}
if(fp->buf)
fp->bufdir = __FILE_BUF_READ;
}
void __fp_buffer_mode_write(FILE *fp)
{
if(__fp_hasbuf_read(fp))
fflush(fp);
if(fp->buf)
fp->bufdir = __FILE_BUF_WRITE;
}
ssize_t __fp_buffered_read(FILE *fp, void *data, size_t request_size)
{
if(!fp->buf || __fp_hasbuf_write(fp))
return -1;
int read_size = min((int)request_size, fp->bufread - fp->bufpos);
if(read_size <= 0)
return 0;
memcpy(data, fp->buf + fp->bufpos, read_size);
fp->bufpos += read_size;
fp->bufungetc = max(fp->bufungetc - read_size, 0);
/* Rewind the buffer if we read it fully */
if(fp->bufpos >= fp->bufread) {
fp->bufread = 0;
fp->bufpos = 0;
/* Clear temporary ungetc() buffers of _IONBF streams */
if(fp->bufmode == _IONBF)
__fp_remove_buffer(fp);
}
return read_size;
}
ssize_t __fp_read(FILE *fp, void *data, size_t size)
{
size_t read_ = 0;
while(read_ < size) {
ssize_t rc = read(fp->fd, data + read_, size - read_);
if(rc < 0) {
fp->error = 1;
return EOF;
}
if(rc == 0) {
fp->eof = 1;
break;
}
fp->fdpos += rc;
read_ += rc;
}
return read_;
}
ssize_t __fp_write(FILE *fp, void const *data, size_t size)
{
size_t written = 0;
while(written < size) {
ssize_t rc = write(fp->fd, data + written, size - written);
if(rc < 0) {
fp->error = 1;
return EOF;
}
if(rc == 0)
break;
fp->fdpos += rc;
written += rc;
}
return written;
}
int __fp_parse_mode(char const *mode, FILE *fp)
{
int base = 0;
bool binary = false;
bool update = false;
for(int i = 0; mode[i]; i++) {
if(mode[i] == 'r' || mode[i] == 'w' || mode[i] == 'a') {
if(base) goto err;
base = mode[i];
}
else if(mode[i] == 'b')
binary = true;
else if(mode[i] == '+')
update = true;
}
if(!base) goto err;
if(fp) {
fp->readable = (base == 'r' || update);
fp->writable = (base == 'w' || base == 'a' || update);
fp->append = (base == 'a');
fp->text = !binary;
}
if(base == 'r')
return (update ? O_RDWR : O_RDONLY);
if(base == 'w')
return (update ? O_RDWR : O_WRONLY) | O_CREAT | O_TRUNC;
if(base == 'a')
return (update ? O_RDWR : O_WRONLY) | O_CREAT;
/* Fallthrough */
err:
errno = EINVAL;
return -1;
}