update xfile
This commit is contained in:
parent
813ce064f3
commit
a0687e29e0
|
@ -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
445
xfile.c
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue