update xfile

This commit is contained in:
Yuichi Nishiwaki 2014-09-09 14:46:56 +09:00
parent 813ce064f3
commit a0687e29e0
2 changed files with 492 additions and 475 deletions

View File

@ -8,6 +8,8 @@ extern "C" {
#include <stddef.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int ungot;
@ -24,52 +26,512 @@ typedef struct {
} xFILE;
/* generic file constructor */
xFILE *xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*flush)(void *), int (*close)(void *));
static inline xFILE *xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*flush)(void *), int (*close)(void *));
/* resource aquisition */
xFILE *xfopen(const char *, const char *);
xFILE *xfpopen(FILE *);
xFILE *xmopen();
int xfclose(xFILE *);
static inline xFILE *xfpopen(FILE *);
static inline xFILE *xmopen();
static inline xFILE *xfopen(const char *, const char *);
static inline int xfclose(xFILE *);
/* buffer management */
int xfflush(xFILE *);
static inline int xfflush(xFILE *);
/* direct IO with buffering */
size_t xfread(void *, size_t, size_t, xFILE *);
size_t xfwrite(const void *, size_t, size_t, xFILE *);
static inline size_t xfread(void *, size_t, size_t, xFILE *);
static inline size_t xfwrite(const void *, size_t, size_t, xFILE *);
/* indicator positioning */
long xfseek(xFILE *, long offset, int whence);
long xftell(xFILE *);
void xrewind(xFILE *);
static inline long xfseek(xFILE *, long offset, int whence);
static inline long xftell(xFILE *);
static inline void xrewind(xFILE *);
/* stream status */
void xclearerr(xFILE *);
int xfeof(xFILE *);
int xferror(xFILE *);
static inline void xclearerr(xFILE *);
static inline int xfeof(xFILE *);
static inline int xferror(xFILE *);
/* character IO */
int xfgetc(xFILE *);
char *xfgets(char *, int, xFILE *);
int xfputc(int, xFILE *);
int xfputs(const char *, xFILE *);
char xgetc(xFILE *);
int xgetchar(void);
int xputc(int, xFILE *);
int xputchar(int);
int xputs(char *);
int xungetc(int, xFILE *);
static inline int xfgetc(xFILE *);
static inline char *xfgets(char *, int, xFILE *);
static inline int xfputc(int, xFILE *);
static inline int xfputs(const char *, xFILE *);
static inline char xgetc(xFILE *);
static inline int xgetchar(void);
static inline int xputc(int, xFILE *);
static inline int xputchar(int);
static inline int xputs(char *);
static inline int xungetc(int, xFILE *);
/* formatted I/O */
int xprintf(const char *, ...);
int xfprintf(xFILE *, const char *, ...);
int xvfprintf(xFILE *, const char *, va_list);
static inline int xprintf(const char *, ...);
static inline int xfprintf(xFILE *, const char *, ...);
static inline int xvfprintf(xFILE *, const char *, va_list);
/* standard I/O */
extern xFILE *xstdin;
extern xFILE *xstdout;
extern xFILE *xstderr;
#define xstdin (xstdin__())
#define xstdout (xstdout__())
#define xstderr (xstderr__())
/* private */
#define XF_EOF 1
#define XF_ERR 2
static inline xFILE *
xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*flush)(void *), int (*close)(void *))
{
xFILE *file;
file = (xFILE *)malloc(sizeof(xFILE));
if (! file) {
return NULL;
}
file->ungot = -1;
file->flags = 0;
/* set vtable */
file->vtable.cookie = cookie;
file->vtable.read = read;
file->vtable.write = write;
file->vtable.seek = seek;
file->vtable.flush = flush;
file->vtable.close = close;
return file;
}
/*
* Derieved xFILE Classes
*/
static inline FILE *
xf_unpack(void *cookie)
{
switch ((long)cookie) {
default: return cookie;
case 0: return stdin;
case 1: return stdout;
case -1: return stderr;
}
}
static inline int
xf_file_read(void *cookie, char *ptr, int size)
{
FILE *file = xf_unpack(cookie);
int r;
r = fread(ptr, 1, size, file);
if (r < size && ferror(file)) {
return -1;
}
if (r == 0 && feof(file)) {
clearerr(file);
}
return r;
}
static inline int
xf_file_write(void *cookie, const char *ptr, int size)
{
FILE *file = xf_unpack(cookie);
int r;
r = fwrite(ptr, 1, size, file);
if (r < size) {
return -1;
}
return r;
}
static inline long
xf_file_seek(void *cookie, long pos, int whence)
{
return fseek(xf_unpack(cookie), pos, whence);
}
static inline int
xf_file_flush(void *cookie)
{
return fflush(xf_unpack(cookie));
}
static inline int
xf_file_close(void *cookie)
{
return fclose(xf_unpack(cookie));
}
static inline xFILE *
xfpopen(FILE *fp)
{
xFILE *file;
file = xfunopen(fp, xf_file_read, xf_file_write, xf_file_seek, xf_file_flush, xf_file_close);
if (! file) {
return NULL;
}
return file;
}
#define XF_FILE_VTABLE xf_file_read, xf_file_write, xf_file_seek, xf_file_flush, xf_file_close
static inline xFILE *
xstdin__()
{
static xFILE xfile_stdin = { -1, 0, { (void *)0, XF_FILE_VTABLE } };
return &xfile_stdin;
}
static inline xFILE *
xstdout__()
{
static xFILE xfile_stdout = { -1, 0, { (void *)1, XF_FILE_VTABLE } };
return &xfile_stdout;
}
static inline xFILE *
xstderr__()
{
static xFILE xfile_stderr = { -1, 0, { (void *)-1, XF_FILE_VTABLE } };
return &xfile_stderr;
}
struct xf_membuf {
char *buf;
long pos, end, capa;
};
static inline int
xf_mem_read(void *cookie, char *ptr, int size)
{
struct xf_membuf *mem;
mem = (struct xf_membuf *)cookie;
if (size > mem->end - mem->pos)
size = mem->end - mem->pos;
memcpy(ptr, mem->buf + mem->pos, size);
mem->pos += size;
return size;
}
static inline int
xf_mem_write(void *cookie, const char *ptr, int size)
{
struct xf_membuf *mem;
mem = (struct xf_membuf *)cookie;
if (mem->pos + size >= mem->capa) {
mem->capa = (mem->pos + size) * 2;
mem->buf = realloc(mem->buf, mem->capa);
}
memcpy(mem->buf + mem->pos, ptr, size);
mem->pos += size;
if (mem->end < mem->pos)
mem->end = mem->pos;
return size;
}
static inline long
xf_mem_seek(void *cookie, long pos, int whence)
{
struct xf_membuf *mem;
mem = (struct xf_membuf *)cookie;
switch (whence) {
case SEEK_SET:
mem->pos = pos;
break;
case SEEK_CUR:
mem->pos += pos;
break;
case SEEK_END:
mem->pos = mem->end + pos;
break;
}
return mem->pos;
}
static inline int
xf_mem_flush(void *cookie)
{
(void)cookie;
return 0;
}
static inline int
xf_mem_close(void *cookie)
{
struct xf_membuf *mem;
mem = (struct xf_membuf *)cookie;
free(mem->buf);
free(mem);
return 0;
}
static inline xFILE *
xmopen()
{
struct xf_membuf *mem;
mem = (struct xf_membuf *)malloc(sizeof(struct xf_membuf));
mem->buf = (char *)malloc(BUFSIZ);
mem->pos = 0;
mem->end = 0;
mem->capa = BUFSIZ;
return xfunopen(mem, xf_mem_read, xf_mem_write, xf_mem_seek, xf_mem_flush, xf_mem_close);
}
#undef XF_FILE_VTABLE
static inline xFILE *
xfopen(const char *filename, const char *mode)
{
FILE *fp;
xFILE *file;
fp = fopen(filename, mode);
if (! fp) {
return NULL;
}
file = xfpopen(fp);
if (! file) {
return NULL;
}
return file;
}
static inline int
xfclose(xFILE *file)
{
int r;
r = file->vtable.close(file->vtable.cookie);
if (r == EOF) {
return -1;
}
free(file);
return 0;
}
static inline int
xfflush(xFILE *file)
{
return file->vtable.flush(file->vtable.cookie);
}
static inline size_t
xfread(void *ptr, size_t block, size_t nitems, xFILE *file)
{
char *dst = (char *)ptr;
char buf[block];
size_t i, offset;
int n;
for (i = 0; i < nitems; ++i) {
offset = 0;
if (file->ungot != -1 && block > 0) {
buf[0] = file->ungot;
offset += 1;
file->ungot = -1;
}
while (offset < block) {
n = file->vtable.read(file->vtable.cookie, buf + offset, block - offset);
if (n < 0) {
file->flags |= XF_ERR;
goto exit;
}
if (n == 0) {
file->flags |= XF_EOF;
goto exit;
}
offset += n;
}
memcpy(dst, buf, block);
dst += block;
}
exit:
return i;
}
static inline size_t
xfwrite(const void *ptr, size_t block, size_t nitems, xFILE *file)
{
char *dst = (char *)ptr;
size_t i, offset;
int n;
for (i = 0; i < nitems; ++i) {
offset = 0;
while (offset < block) {
n = file->vtable.write(file->vtable.cookie, dst + offset, block - offset);
if (n < 0) {
file->flags |= XF_ERR;
goto exit;
}
offset += n;
}
dst += block;
}
exit:
return i;
}
static inline long
xfseek(xFILE *file, long offset, int whence)
{
file->ungot = -1;
return file->vtable.seek(file->vtable.cookie, offset, whence);
}
static inline long
xftell(xFILE *file)
{
return xfseek(file, 0, SEEK_CUR);
}
static inline void
xrewind(xFILE *file)
{
xfseek(file, 0, SEEK_SET);
}
static inline void
xclearerr(xFILE *file)
{
file->flags = 0;
}
static inline int
xfeof(xFILE *file)
{
return file->flags & XF_EOF;
}
static inline int
xferror(xFILE *file)
{
return file->flags & XF_ERR;
}
static inline int
xfgetc(xFILE *file)
{
char buf[1];
xfread(buf, 1, 1, file);
if (xfeof(file)) {
return EOF;
}
return buf[0];
}
static inline int
xungetc(int c, xFILE *file)
{
file->ungot = c;
if (c != EOF) {
file->flags &= ~XF_EOF;
}
return c;
}
static inline int
xgetchar(void)
{
return xfgetc(xstdin);
}
static inline int
xfputc(int c, xFILE *file)
{
char buf[1];
buf[0] = c;
xfwrite(buf, 1, 1, file);
return buf[0];
}
static inline int
xputchar(int c)
{
return xfputc(c, xstdout);
}
static inline int
xfputs(const char *str, xFILE *file)
{
int len;
len = strlen(str);
xfwrite(str, len, 1, file);
return 0;
}
static inline int
xprintf(const char *fmt, ...)
{
va_list ap;
int n;
va_start(ap, fmt);
n = xvfprintf(xstdout, fmt, ap);
va_end(ap);
return n;
}
static inline int
xfprintf(xFILE *stream, const char *fmt, ...)
{
va_list ap;
int n;
va_start(ap, fmt);
n = xvfprintf(stream, fmt, ap);
va_end(ap);
return n;
}
static inline int
xvfprintf(xFILE *stream, const char *fmt, va_list ap)
{
va_list ap2;
va_copy(ap2, ap);
{
char buf[vsnprintf(NULL, 0, fmt, ap2)];
vsnprintf(buf, sizeof buf + 1, fmt, ap);
if (xfwrite(buf, sizeof buf, 1, stream) < 1) {
return -1;
}
va_end(ap2);
return sizeof buf;
}
}
#if defined(__cplusplus)
}

445
xfile.c
View File

@ -1,445 +0,0 @@
#include "picrin/xfile.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#define min(a,b) (((a)>(b))?(b):(a))
#define max(a,b) (((a)<(b))?(b):(a))
#define XF_EOF 1
#define XF_ERR 2
xFILE *
xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*flush)(void *), int (*close)(void *))
{
xFILE *file;
file = (xFILE *)malloc(sizeof(xFILE));
if (! file) {
return NULL;
}
file->ungot = -1;
file->flags = 0;
/* set vtable */
file->vtable.cookie = cookie;
file->vtable.read = read;
file->vtable.write = write;
file->vtable.seek = seek;
file->vtable.flush = flush;
file->vtable.close = close;
return file;
}
xFILE *
xfopen(const char *filename, const char *mode)
{
FILE *fp;
xFILE *file;
fp = fopen(filename, mode);
if (! fp) {
return NULL;
}
file = xfpopen(fp);
if (! file) {
return NULL;
}
return file;
}
int
xfclose(xFILE *file)
{
int r;
r = file->vtable.close(file->vtable.cookie);
if (r == EOF) {
return -1;
}
free(file);
return 0;
}
int
xfflush(xFILE *file)
{
return file->vtable.flush(file->vtable.cookie);
}
size_t
xfread(void *ptr, size_t block, size_t nitems, xFILE *file)
{
char *dst = (char *)ptr;
char buf[block];
size_t i, offset;
int n;
for (i = 0; i < nitems; ++i) {
offset = 0;
if (file->ungot != -1 && block > 0) {
buf[0] = file->ungot;
offset += 1;
file->ungot = -1;
}
while (offset < block) {
n = file->vtable.read(file->vtable.cookie, buf + offset, block - offset);
if (n < 0) {
file->flags |= XF_ERR;
goto exit;
}
if (n == 0) {
file->flags |= XF_EOF;
goto exit;
}
offset += n;
}
memcpy(dst, buf, block);
dst += block;
}
exit:
return i;
}
size_t
xfwrite(const void *ptr, size_t block, size_t nitems, xFILE *file)
{
char *dst = (char *)ptr;
size_t i, offset;
int n;
for (i = 0; i < nitems; ++i) {
offset = 0;
while (offset < block) {
n = file->vtable.write(file->vtable.cookie, dst + offset, block - offset);
if (n < 0) {
file->flags |= XF_ERR;
goto exit;
}
offset += n;
}
dst += block;
}
exit:
return i;
}
long
xfseek(xFILE *file, long offset, int whence)
{
file->ungot = -1;
return file->vtable.seek(file->vtable.cookie, offset, whence);
}
long
xftell(xFILE *file)
{
return xfseek(file, 0, SEEK_CUR);
}
void
xrewind(xFILE *file)
{
xfseek(file, 0, SEEK_SET);
}
void
xclearerr(xFILE *file)
{
file->flags = 0;
}
int
xfeof(xFILE *file)
{
return file->flags & XF_EOF;
}
int
xferror(xFILE *file)
{
return file->flags & XF_ERR;
}
int
xfgetc(xFILE *file)
{
char buf[1];
xfread(buf, 1, 1, file);
if (xfeof(file)) {
return EOF;
}
return buf[0];
}
int
xungetc(int c, xFILE *file)
{
file->ungot = c;
if (c != EOF) {
file->flags &= ~XF_EOF;
}
return c;
}
int
xgetchar(void)
{
return xfgetc(xstdin);
}
int
xfputc(int c, xFILE *file)
{
char buf[1];
buf[0] = c;
xfwrite(buf, 1, 1, file);
return buf[0];
}
int
xputchar(int c)
{
return xfputc(c, xstdout);
}
int
xfputs(const char *str, xFILE *file)
{
int len;
len = strlen(str);
xfwrite(str, len, 1, file);
return 0;
}
int
xprintf(const char *fmt, ...)
{
va_list ap;
int n;
va_start(ap, fmt);
n = xvfprintf(xstdout, fmt, ap);
va_end(ap);
return n;
}
int
xfprintf(xFILE *stream, const char *fmt, ...)
{
va_list ap;
int n;
va_start(ap, fmt);
n = xvfprintf(stream, fmt, ap);
va_end(ap);
return n;
}
int
xvfprintf(xFILE *stream, const char *fmt, va_list ap)
{
va_list ap2;
va_copy(ap2, ap);
{
char buf[vsnprintf(NULL, 0, fmt, ap2)];
vsnprintf(buf, sizeof buf + 1, fmt, ap);
if (xfwrite(buf, sizeof buf, 1, stream) < 1) {
return -1;
}
va_end(ap2);
return sizeof buf;
}
}
/*
* Derieved xFILE Classes
*/
static FILE *
unpack(void *cookie)
{
switch ((long)cookie) {
default: return cookie;
case 0: return stdin;
case 1: return stdout;
case -1: return stderr;
}
}
static int
file_read(void *cookie, char *ptr, int size)
{
FILE *file = unpack(cookie);
int r;
r = fread(ptr, 1, size, file);
if (r < size && ferror(file)) {
return -1;
}
if (r == 0 && feof(file)) {
clearerr(file);
}
return r;
}
static int
file_write(void *cookie, const char *ptr, int size)
{
FILE *file = unpack(cookie);
int r;
r = fwrite(ptr, 1, size, file);
if (r < size) {
return -1;
}
return r;
}
static long
file_seek(void *cookie, long pos, int whence)
{
return fseek(unpack(cookie), pos, whence);
}
static int
file_flush(void *cookie)
{
return fflush(unpack(cookie));
}
static int
file_close(void *cookie)
{
return fclose(unpack(cookie));
}
xFILE *
xfpopen(FILE *fp)
{
xFILE *file;
file = xfunopen(fp, file_read, file_write, file_seek, file_flush, file_close);
if (! file) {
return NULL;
}
return file;
}
#define FILE_VTABLE file_read, file_write, file_seek, file_flush, file_close
static xFILE xfile_stdin = { -1, 0, { (void *)0, FILE_VTABLE } };
static xFILE xfile_stdout = { -1, 0, { (void *)1, FILE_VTABLE } };
static xFILE xfile_stderr = { -1, 0, { (void *)-1, FILE_VTABLE } };
xFILE *xstdin = &xfile_stdin;
xFILE *xstdout = &xfile_stdout;
xFILE *xstderr = &xfile_stderr;
struct membuf {
char *buf;
long pos, end, capa;
};
static int
mem_read(void *cookie, char *ptr, int size)
{
struct membuf *mem;
mem = (struct membuf *)cookie;
size = min(size, mem->end - mem->pos);
memcpy(ptr, mem->buf + mem->pos, size);
mem->pos += size;
return size;
}
static int
mem_write(void *cookie, const char *ptr, int size)
{
struct membuf *mem;
mem = (struct membuf *)cookie;
if (mem->pos + size >= mem->capa) {
mem->capa = (mem->pos + size) * 2;
mem->buf = realloc(mem->buf, mem->capa);
}
memcpy(mem->buf + mem->pos, ptr, size);
mem->pos += size;
mem->end = max(mem->pos, mem->end);
return size;
}
static long
mem_seek(void *cookie, long pos, int whence)
{
struct membuf *mem;
mem = (struct membuf *)cookie;
switch (whence) {
case SEEK_SET:
mem->pos = pos;
break;
case SEEK_CUR:
mem->pos += pos;
break;
case SEEK_END:
mem->pos = mem->end + pos;
break;
}
return mem->pos;
}
static int
mem_flush(void *cookie)
{
(void)cookie;
return 0;
}
static int
mem_close(void *cookie)
{
struct membuf *mem;
mem = (struct membuf *)cookie;
free(mem->buf);
free(mem);
return 0;
}
xFILE *
xmopen()
{
struct membuf *mem;
mem = (struct membuf *)malloc(sizeof(struct membuf));
mem->buf = (char *)malloc(BUFSIZ);
mem->pos = 0;
mem->end = 0;
mem->capa = BUFSIZ;
return xfunopen(mem, mem_read, mem_write, mem_seek, mem_flush, mem_close);
}