xfile completely refactored
This commit is contained in:
parent
329251d984
commit
00cde353ba
|
@ -32,8 +32,6 @@ extern "C" {
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "picrin/config.h"
|
#include "picrin/config.h"
|
||||||
#include "picrin/util.h"
|
#include "picrin/util.h"
|
||||||
#include "picrin/compat.h"
|
#include "picrin/compat.h"
|
||||||
|
|
|
@ -156,6 +156,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
# include <stdio.h>
|
||||||
# define GC_STRESS 0
|
# define GC_STRESS 0
|
||||||
# define VM_DEBUG 1
|
# define VM_DEBUG 1
|
||||||
# define GC_DEBUG 0
|
# define GC_DEBUG 0
|
||||||
|
|
|
@ -5,632 +5,104 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifndef NULL
|
||||||
|
# define NULL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef EOF
|
||||||
|
# define EOF (-1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define XBUFSIZ 1024
|
||||||
|
#define XOPEN_MAX 1024
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int ungot;
|
/* buffer */
|
||||||
int flags;
|
char buf[1]; /* fallback buffer */
|
||||||
|
long cnt; /* characters left */
|
||||||
|
char *ptr; /* next character position */
|
||||||
|
char *base; /* location of the buffer */
|
||||||
/* operators */
|
/* operators */
|
||||||
struct {
|
struct {
|
||||||
void *cookie;
|
void *cookie;
|
||||||
int (*read)(void *, char *, int);
|
int (*read)(void *, char *, int);
|
||||||
int (*write)(void *, const char *, int);
|
int (*write)(void *, const char *, int);
|
||||||
long (*seek)(void *, long, int);
|
long (*seek)(void *, long, int);
|
||||||
int (*flush)(void *);
|
|
||||||
int (*close)(void *);
|
int (*close)(void *);
|
||||||
} vtable;
|
} vtable;
|
||||||
|
int flag; /* mode of the file access */
|
||||||
} xFILE;
|
} xFILE;
|
||||||
|
|
||||||
/* generic file constructor */
|
extern xFILE x_iob[XOPEN_MAX];
|
||||||
PIC_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 */
|
#define xstdin (x_iob[0].vtable.cookie || (x_iob[0].vtable.cookie = stdin ), &x_iob[0])
|
||||||
PIC_INLINE xFILE *xfpopen(FILE *);
|
#define xstdout (x_iob[1].vtable.cookie || (x_iob[1].vtable.cookie = stdout), &x_iob[1])
|
||||||
PIC_INLINE xFILE *xmopen();
|
#define xstderr (x_iob[2].vtable.cookie || (x_iob[2].vtable.cookie = stderr), &x_iob[2])
|
||||||
PIC_INLINE xFILE *xfopen(const char *, const char *);
|
|
||||||
PIC_INLINE int xfclose(xFILE *);
|
|
||||||
|
|
||||||
/* buffer management */
|
enum _flags {
|
||||||
PIC_INLINE int xfflush(xFILE *);
|
X_READ = 01,
|
||||||
|
X_WRITE = 02,
|
||||||
/* direct IO with buffering */
|
X_UNBUF = 04,
|
||||||
PIC_INLINE size_t xfread(void *, size_t, size_t, xFILE *);
|
X_EOF = 010,
|
||||||
PIC_INLINE size_t xfwrite(const void *, size_t, size_t, xFILE *);
|
X_ERR = 020,
|
||||||
|
X_LNBUF = 040
|
||||||
/* indicator positioning */
|
|
||||||
PIC_INLINE long xfseek(xFILE *, long offset, int whence);
|
|
||||||
PIC_INLINE long xftell(xFILE *);
|
|
||||||
PIC_INLINE void xrewind(xFILE *);
|
|
||||||
|
|
||||||
/* stream status */
|
|
||||||
PIC_INLINE void xclearerr(xFILE *);
|
|
||||||
PIC_INLINE int xfeof(xFILE *);
|
|
||||||
PIC_INLINE int xferror(xFILE *);
|
|
||||||
|
|
||||||
/* character IO */
|
|
||||||
PIC_INLINE int xfgetc(xFILE *);
|
|
||||||
PIC_INLINE char *xfgets(char *, int, xFILE *);
|
|
||||||
PIC_INLINE int xfputc(int, xFILE *);
|
|
||||||
PIC_INLINE int xfputs(const char *, xFILE *);
|
|
||||||
PIC_INLINE int xgetc(xFILE *);
|
|
||||||
PIC_INLINE int xgetchar(void);
|
|
||||||
PIC_INLINE int xputc(int, xFILE *);
|
|
||||||
PIC_INLINE int xputchar(int);
|
|
||||||
PIC_INLINE int xputs(const char *);
|
|
||||||
PIC_INLINE int xungetc(int, xFILE *);
|
|
||||||
|
|
||||||
/* formatted I/O */
|
|
||||||
PIC_INLINE int xprintf(const char *, ...);
|
|
||||||
PIC_INLINE int xfprintf(xFILE *, const char *, ...);
|
|
||||||
PIC_INLINE int xvfprintf(xFILE *, const char *, va_list);
|
|
||||||
|
|
||||||
/* standard I/O */
|
|
||||||
#define xstdin (xstdin_())
|
|
||||||
#define xstdout (xstdout_())
|
|
||||||
#define xstderr (xstderr_())
|
|
||||||
|
|
||||||
|
|
||||||
/* private */
|
|
||||||
|
|
||||||
#define XF_EOF 1
|
|
||||||
#define XF_ERR 2
|
|
||||||
|
|
||||||
PIC_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
|
|
||||||
*/
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xf_file_read(void *cookie, char *ptr, int size)
|
|
||||||
{
|
|
||||||
FILE *file = cookie;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
r = (int)fread(ptr, 1, (size_t)size, file);
|
|
||||||
if (r < size && ferror(file)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (r == 0 && feof(file)) {
|
|
||||||
clearerr(file);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xf_file_write(void *cookie, const char *ptr, int size)
|
|
||||||
{
|
|
||||||
FILE *file = cookie;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
r = (int)fwrite(ptr, 1, (size_t)size, file);
|
|
||||||
if (r < size) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE long
|
|
||||||
xf_file_seek(void *cookie, long pos, int whence)
|
|
||||||
{
|
|
||||||
return fseek(cookie, pos, whence);
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xf_file_flush(void *cookie)
|
|
||||||
{
|
|
||||||
return fflush(cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xf_file_close(void *cookie)
|
|
||||||
{
|
|
||||||
return fclose(cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_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
|
|
||||||
|
|
||||||
PIC_INLINE xFILE *
|
|
||||||
xstdin_()
|
|
||||||
{
|
|
||||||
static xFILE x = { -1, 0, { NULL, XF_FILE_VTABLE } };
|
|
||||||
|
|
||||||
if (! x.vtable.cookie) {
|
|
||||||
x.vtable.cookie = stdin;
|
|
||||||
}
|
|
||||||
return &x;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE xFILE *
|
|
||||||
xstdout_()
|
|
||||||
{
|
|
||||||
static xFILE x = { -1, 0, { NULL, XF_FILE_VTABLE } };
|
|
||||||
|
|
||||||
if (! x.vtable.cookie) {
|
|
||||||
x.vtable.cookie = stdout;
|
|
||||||
}
|
|
||||||
return &x;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE xFILE *
|
|
||||||
xstderr_()
|
|
||||||
{
|
|
||||||
static xFILE x = { -1, 0, { NULL, XF_FILE_VTABLE } };
|
|
||||||
|
|
||||||
if (! x.vtable.cookie) {
|
|
||||||
x.vtable.cookie = stderr;
|
|
||||||
}
|
|
||||||
return &x;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct xf_membuf {
|
|
||||||
char *buf;
|
|
||||||
long pos, end, capa;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PIC_INLINE int
|
#define xclearerr(p) ((p)->flag &= ~(X_EOF | X_ERR))
|
||||||
xf_mem_read(void *cookie, char *ptr, int size)
|
#define xfeof(p) (((p)->flag & X_EOF) != 0)
|
||||||
{
|
#define xferror(p) (((p)->flag & X_ERR) != 0)
|
||||||
struct xf_membuf *mem;
|
#define xfileno(p) ((p)->fd)
|
||||||
|
|
||||||
mem = (struct xf_membuf *)cookie;
|
#define xgetc(p) \
|
||||||
|
((--(p)->cnt >= 0) \
|
||||||
if (size > (int)(mem->end - mem->pos))
|
? (unsigned char) *(p)->ptr++ \
|
||||||
size = (int)(mem->end - mem->pos);
|
: x_fillbuf(p))
|
||||||
memcpy(ptr, mem->buf + mem->pos, size);
|
#define xputc(x, p) \
|
||||||
mem->pos += size;
|
((--(p)->cnt >= 0 && !(((p)->flag & X_LNBUF) && (x) == '\n')) \
|
||||||
return size;
|
? *(p)->ptr++ = (x) \
|
||||||
}
|
: x_flushbuf(x, (p)))
|
||||||
|
#define xgetchar() xgetc(xstdin)
|
||||||
PIC_INLINE int
|
#define xputchar(x) xputc((x), xstdout)
|
||||||
xf_mem_write(void *cookie, const char *ptr, int size)
|
|
||||||
{
|
/* resource aquisition */
|
||||||
struct xf_membuf *mem;
|
xFILE *xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*close)(void *));
|
||||||
|
xFILE *xfopen(const char *, const char *);
|
||||||
mem = (struct xf_membuf *)cookie;
|
int xfclose(xFILE *);
|
||||||
|
|
||||||
if (mem->pos + size >= mem->capa) {
|
/* buffer management */
|
||||||
mem->capa = (mem->pos + size) * 2;
|
int x_fillbuf(xFILE *);
|
||||||
mem->buf = realloc(mem->buf, (size_t)mem->capa);
|
int x_flushbuf(int, xFILE *);
|
||||||
}
|
int xfflush(xFILE *);
|
||||||
memcpy(mem->buf + mem->pos, ptr, size);
|
|
||||||
mem->pos += size;
|
/* direct IO */
|
||||||
if (mem->end < mem->pos)
|
size_t xfread(void *, size_t, size_t, xFILE *);
|
||||||
mem->end = mem->pos;
|
size_t xfwrite(const void *, size_t, size_t, xFILE *);
|
||||||
return size;
|
|
||||||
}
|
enum {
|
||||||
|
XSEEK_CUR,
|
||||||
PIC_INLINE long
|
XSEEK_END,
|
||||||
xf_mem_seek(void *cookie, long pos, int whence)
|
XSEEK_SET
|
||||||
{
|
};
|
||||||
struct xf_membuf *mem;
|
|
||||||
|
/* indicator positioning */
|
||||||
mem = (struct xf_membuf *)cookie;
|
long xfseek(xFILE *, long, int);
|
||||||
|
long xftell(xFILE *);
|
||||||
switch (whence) {
|
void xrewind(xFILE *);
|
||||||
case SEEK_SET:
|
|
||||||
mem->pos = pos;
|
/* character IO */
|
||||||
break;
|
int xfputc(int, xFILE *);
|
||||||
case SEEK_CUR:
|
int xfgetc(xFILE *);
|
||||||
mem->pos += pos;
|
int xfputs(const char *, xFILE *);
|
||||||
break;
|
char *xfgets(char *, int, xFILE *);
|
||||||
case SEEK_END:
|
int xputs(const char *);
|
||||||
mem->pos = mem->end + pos;
|
int xungetc(int, xFILE *);
|
||||||
break;
|
|
||||||
}
|
/* formatted I/O */
|
||||||
|
int xprintf(const char *, ...);
|
||||||
return mem->pos;
|
int xfprintf(xFILE *, const char *, ...);
|
||||||
}
|
int xvfprintf(xFILE *, const char *, va_list);
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xf_mem_flush(void *cookie)
|
|
||||||
{
|
|
||||||
(void)cookie;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xf_mem_close(void *cookie)
|
|
||||||
{
|
|
||||||
struct xf_membuf *mem;
|
|
||||||
|
|
||||||
mem = (struct xf_membuf *)cookie;
|
|
||||||
free(mem->buf);
|
|
||||||
free(mem);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_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
|
|
||||||
|
|
||||||
PIC_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xfclose(xFILE *file)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
|
|
||||||
r = file->vtable.close(file->vtable.cookie);
|
|
||||||
if (r == EOF) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(file);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xfflush(xFILE *file)
|
|
||||||
{
|
|
||||||
return file->vtable.flush(file->vtable.cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE size_t
|
|
||||||
xfread(void *ptr, size_t block, size_t nitems, xFILE *file)
|
|
||||||
{
|
|
||||||
char cbuf[256], *buf;
|
|
||||||
char *dst = (char *)ptr;
|
|
||||||
size_t i, offset;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if (block <= 256) {
|
|
||||||
buf = cbuf;
|
|
||||||
} else {
|
|
||||||
buf = malloc(block);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < nitems; ++i) {
|
|
||||||
offset = 0;
|
|
||||||
if (file->ungot != -1 && block > 0) {
|
|
||||||
buf[0] = (char)file->ungot;
|
|
||||||
offset += 1;
|
|
||||||
file->ungot = -1;
|
|
||||||
}
|
|
||||||
while (offset < block) {
|
|
||||||
n = file->vtable.read(file->vtable.cookie, buf + offset, (int)(block - offset));
|
|
||||||
if (n < 0) {
|
|
||||||
file->flags |= XF_ERR;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (n == 0) {
|
|
||||||
file->flags |= XF_EOF;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
offset += (unsigned)n;
|
|
||||||
}
|
|
||||||
memcpy(dst, buf, block);
|
|
||||||
dst += block;
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
|
|
||||||
if (cbuf != buf) {
|
|
||||||
free(buf);
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_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, (int)(block - offset));
|
|
||||||
if (n < 0) {
|
|
||||||
file->flags |= XF_ERR;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
offset += (unsigned)n;
|
|
||||||
}
|
|
||||||
dst += block;
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE long
|
|
||||||
xfseek(xFILE *file, long offset, int whence)
|
|
||||||
{
|
|
||||||
file->ungot = -1;
|
|
||||||
return file->vtable.seek(file->vtable.cookie, offset, whence);
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE long
|
|
||||||
xftell(xFILE *file)
|
|
||||||
{
|
|
||||||
return xfseek(file, 0, SEEK_CUR);
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE void
|
|
||||||
xrewind(xFILE *file)
|
|
||||||
{
|
|
||||||
xfseek(file, 0, SEEK_SET);
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE void
|
|
||||||
xclearerr(xFILE *file)
|
|
||||||
{
|
|
||||||
file->flags = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xfeof(xFILE *file)
|
|
||||||
{
|
|
||||||
return file->flags & XF_EOF;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xferror(xFILE *file)
|
|
||||||
{
|
|
||||||
return file->flags & XF_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xfgetc(xFILE *file)
|
|
||||||
{
|
|
||||||
char buf[1];
|
|
||||||
|
|
||||||
xfread(buf, 1, 1, file);
|
|
||||||
|
|
||||||
if (xfeof(file) || xferror(file)) {
|
|
||||||
return EOF;
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xgetc(xFILE *file)
|
|
||||||
{
|
|
||||||
return xfgetc(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE char *
|
|
||||||
xfgets(char *str, int size, xFILE *file)
|
|
||||||
{
|
|
||||||
int c = EOF, i;
|
|
||||||
|
|
||||||
for (i = 0; i < size - 1 && c != '\n'; ++i) {
|
|
||||||
if ((c = xfgetc(file)) == EOF) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
str[i] = (char)c;
|
|
||||||
}
|
|
||||||
if (i == 0 && c == EOF) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (xferror(file)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
str[i] = '\0';
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xungetc(int c, xFILE *file)
|
|
||||||
{
|
|
||||||
file->ungot = c;
|
|
||||||
if (c != EOF) {
|
|
||||||
file->flags &= ~XF_EOF;
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xgetchar(void)
|
|
||||||
{
|
|
||||||
return xfgetc(xstdin);
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xfputc(int c, xFILE *file)
|
|
||||||
{
|
|
||||||
char buf[1];
|
|
||||||
|
|
||||||
buf[0] = (char)c;
|
|
||||||
xfwrite(buf, 1, 1, file);
|
|
||||||
|
|
||||||
if (xferror(file)) {
|
|
||||||
return EOF;
|
|
||||||
}
|
|
||||||
return buf[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xputc(int c, xFILE *file)
|
|
||||||
{
|
|
||||||
return xfputc(c, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xputchar(int c)
|
|
||||||
{
|
|
||||||
return xfputc(c, xstdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xfputs(const char *str, xFILE *file)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
len = strlen(str);
|
|
||||||
xfwrite(str, len, 1, file);
|
|
||||||
|
|
||||||
if (xferror(file)) {
|
|
||||||
return EOF;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xputs(const char *s)
|
|
||||||
{
|
|
||||||
return xfputs(s, xstdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_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 void
|
|
||||||
xfile_printint(xFILE *stream, long x, int base)
|
|
||||||
{
|
|
||||||
static char digits[] = "0123456789abcdef";
|
|
||||||
char buf[20];
|
|
||||||
int i, neg;
|
|
||||||
|
|
||||||
neg = 0;
|
|
||||||
if (x < 0) {
|
|
||||||
neg = 1;
|
|
||||||
x = -x;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
do {
|
|
||||||
buf[i++] = digits[x % base];
|
|
||||||
} while ((x /= base) != 0);
|
|
||||||
|
|
||||||
if (neg) {
|
|
||||||
buf[i++] = '-';
|
|
||||||
}
|
|
||||||
|
|
||||||
while (i-- > 0) {
|
|
||||||
xputc(buf[i], stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PIC_INLINE int
|
|
||||||
xvfprintf(xFILE *stream, const char *fmt, va_list ap)
|
|
||||||
{
|
|
||||||
const char *p;
|
|
||||||
char *sval;
|
|
||||||
int ival;
|
|
||||||
double dval;
|
|
||||||
void *vp;
|
|
||||||
long seekr = xftell(stream);
|
|
||||||
|
|
||||||
for (p = fmt; *p; p++) {
|
|
||||||
if (*p != '%') {
|
|
||||||
xputc(*p, stream);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
switch (*++p) {
|
|
||||||
case 'd':
|
|
||||||
case 'i':
|
|
||||||
ival = va_arg(ap, int);
|
|
||||||
xfile_printint(stream, ival, 10);
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
dval = va_arg(ap, double);
|
|
||||||
xfile_printint(stream, dval, 10);
|
|
||||||
xputc('.', stream);
|
|
||||||
xfile_printint(stream, fabs((dval - (int)dval) * 1e4), 10);
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
sval = va_arg(ap, char*);
|
|
||||||
xfputs(sval, stream);
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
vp = va_arg(ap, void*);
|
|
||||||
xfputs("0x", stream);
|
|
||||||
xfile_printint(stream, (long)vp, 16);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
xputc(*(p-1), stream);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return xftell(stream) - seekr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ struct strfile {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
strfile_read(void *cookie, char *ptr, int size)
|
string_read(void *cookie, char *ptr, int size)
|
||||||
{
|
{
|
||||||
struct strfile *m = cookie;
|
struct strfile *m = cookie;
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ strfile_read(void *cookie, char *ptr, int size)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
strfile_write(void *cookie, const char *ptr, int size)
|
string_write(void *cookie, const char *ptr, int size)
|
||||||
{
|
{
|
||||||
struct strfile *m = cookie;
|
struct strfile *m = cookie;
|
||||||
|
|
||||||
|
@ -96,18 +96,18 @@ strfile_write(void *cookie, const char *ptr, int size)
|
||||||
}
|
}
|
||||||
|
|
||||||
static long
|
static long
|
||||||
strfile_seek(void *cookie, long pos, int whence)
|
string_seek(void *cookie, long pos, int whence)
|
||||||
{
|
{
|
||||||
struct strfile *m = cookie;
|
struct strfile *m = cookie;
|
||||||
|
|
||||||
switch (whence) {
|
switch (whence) {
|
||||||
case SEEK_SET:
|
case XSEEK_SET:
|
||||||
m->pos = pos;
|
m->pos = pos;
|
||||||
break;
|
break;
|
||||||
case SEEK_CUR:
|
case XSEEK_CUR:
|
||||||
m->pos += pos;
|
m->pos += pos;
|
||||||
break;
|
break;
|
||||||
case SEEK_END:
|
case XSEEK_END:
|
||||||
m->pos = m->end + pos;
|
m->pos = m->end + pos;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -116,15 +116,7 @@ strfile_seek(void *cookie, long pos, int whence)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
strfile_flush(void *cookie)
|
string_close(void *cookie)
|
||||||
{
|
|
||||||
(void)cookie;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
strfile_close(void *cookie)
|
|
||||||
{
|
{
|
||||||
struct strfile *m = cookie;
|
struct strfile *m = cookie;
|
||||||
|
|
||||||
|
@ -134,9 +126,8 @@ strfile_close(void *cookie)
|
||||||
}
|
}
|
||||||
|
|
||||||
static xFILE *
|
static xFILE *
|
||||||
strfile_open(pic_state *pic)
|
string_open(pic_state *pic, const char *data, size_t size)
|
||||||
{
|
{
|
||||||
static const size_t size = 128;
|
|
||||||
struct strfile *m;
|
struct strfile *m;
|
||||||
xFILE *file;
|
xFILE *file;
|
||||||
|
|
||||||
|
@ -144,12 +135,19 @@ strfile_open(pic_state *pic)
|
||||||
m->pic = pic;
|
m->pic = pic;
|
||||||
m->buf = pic_malloc(pic, size);
|
m->buf = pic_malloc(pic, size);
|
||||||
m->pos = 0;
|
m->pos = 0;
|
||||||
m->end = 0;
|
m->end = size;
|
||||||
m->capa = size;
|
m->capa = size;
|
||||||
|
|
||||||
file = xfunopen(m, strfile_read, strfile_write, strfile_seek, strfile_flush, strfile_close);
|
memcpy(m->buf, data, size);
|
||||||
|
|
||||||
|
if (data != NULL) {
|
||||||
|
file = xfunopen(m, string_read, NULL, string_seek, string_close);
|
||||||
|
} else {
|
||||||
|
file = xfunopen(m, NULL, string_write, string_seek, string_close);
|
||||||
|
}
|
||||||
|
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
strfile_close(m);
|
string_close(m);
|
||||||
pic_error(pic, "could not open new output string/bytevector port", pic_nil_value());
|
pic_error(pic, "could not open new output string/bytevector port", pic_nil_value());
|
||||||
}
|
}
|
||||||
return file;
|
return file;
|
||||||
|
@ -161,14 +159,10 @@ pic_open_input_string(pic_state *pic, const char *str)
|
||||||
struct pic_port *port;
|
struct pic_port *port;
|
||||||
|
|
||||||
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
|
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
|
||||||
port->file = strfile_open(pic);
|
port->file = string_open(pic, str, strlen(str));
|
||||||
port->flags = PIC_PORT_IN | PIC_PORT_TEXT;
|
port->flags = PIC_PORT_IN | PIC_PORT_TEXT;
|
||||||
port->status = PIC_PORT_OPEN;
|
port->status = PIC_PORT_OPEN;
|
||||||
|
|
||||||
xfputs(str, port->file);
|
|
||||||
xfflush(port->file);
|
|
||||||
xrewind(port->file);
|
|
||||||
|
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +172,7 @@ pic_open_output_string(pic_state *pic)
|
||||||
struct pic_port *port;
|
struct pic_port *port;
|
||||||
|
|
||||||
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
|
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
|
||||||
port->file = strfile_open(pic);
|
port->file = string_open(pic, NULL, 0);
|
||||||
port->flags = PIC_PORT_OUT | PIC_PORT_TEXT;
|
port->flags = PIC_PORT_OUT | PIC_PORT_TEXT;
|
||||||
port->status = PIC_PORT_OPEN;
|
port->status = PIC_PORT_OPEN;
|
||||||
|
|
||||||
|
@ -188,20 +182,17 @@ pic_open_output_string(pic_state *pic)
|
||||||
struct pic_string *
|
struct pic_string *
|
||||||
pic_get_output_string(pic_state *pic, struct pic_port *port)
|
pic_get_output_string(pic_state *pic, struct pic_port *port)
|
||||||
{
|
{
|
||||||
size_t size;
|
struct strfile *s;
|
||||||
char *buf;
|
|
||||||
|
if (port->file->vtable.write != string_write) {
|
||||||
|
pic_errorf(pic, "get-output-string: port is not made by open-output-string");
|
||||||
|
}
|
||||||
|
|
||||||
/* get endpos */
|
|
||||||
xfflush(port->file);
|
xfflush(port->file);
|
||||||
size = (size_t)xftell(port->file);
|
|
||||||
xrewind(port->file);
|
|
||||||
|
|
||||||
/* copy to buf */
|
s = port->file->vtable.cookie;
|
||||||
buf = (char *)pic_malloc(pic, size + 1);
|
|
||||||
buf[size] = 0;
|
|
||||||
xfread(buf, size, 1, port->file);
|
|
||||||
|
|
||||||
return pic_make_str(pic, buf, size);
|
return pic_make_str(pic, s->buf, s->end);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -417,14 +408,10 @@ pic_port_open_input_blob(pic_state *pic)
|
||||||
pic_get_args(pic, "b", &blob);
|
pic_get_args(pic, "b", &blob);
|
||||||
|
|
||||||
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
|
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
|
||||||
port->file = strfile_open(pic);
|
port->file = string_open(pic, (const char *)blob->data, blob->len);
|
||||||
port->flags = PIC_PORT_IN | PIC_PORT_BINARY;
|
port->flags = PIC_PORT_IN | PIC_PORT_BINARY;
|
||||||
port->status = PIC_PORT_OPEN;
|
port->status = PIC_PORT_OPEN;
|
||||||
|
|
||||||
xfwrite(blob->data, 1, blob->len, port->file);
|
|
||||||
xfflush(port->file);
|
|
||||||
xrewind(port->file);
|
|
||||||
|
|
||||||
return pic_obj_value(port);
|
return pic_obj_value(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,7 +423,7 @@ pic_port_open_output_bytevector(pic_state *pic)
|
||||||
pic_get_args(pic, "");
|
pic_get_args(pic, "");
|
||||||
|
|
||||||
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
|
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
|
||||||
port->file = strfile_open(pic);
|
port->file = string_open(pic, NULL, 0);
|
||||||
port->flags = PIC_PORT_OUT | PIC_PORT_BINARY;
|
port->flags = PIC_PORT_OUT | PIC_PORT_BINARY;
|
||||||
port->status = PIC_PORT_OPEN;
|
port->status = PIC_PORT_OPEN;
|
||||||
|
|
||||||
|
@ -448,20 +435,22 @@ pic_port_get_output_bytevector(pic_state *pic)
|
||||||
{
|
{
|
||||||
struct pic_port *port = pic_stdout(pic);
|
struct pic_port *port = pic_stdout(pic);
|
||||||
pic_blob *blob;
|
pic_blob *blob;
|
||||||
size_t size;
|
struct strfile *s;
|
||||||
|
|
||||||
pic_get_args(pic, "|p", &port);
|
pic_get_args(pic, "|p", &port);
|
||||||
|
|
||||||
assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_BINARY, PIC_PORT_OPEN, "get-output-bytevector");
|
assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_BINARY, PIC_PORT_OPEN, "get-output-bytevector");
|
||||||
|
|
||||||
/* get endpos */
|
if (port->file->vtable.write != string_write) {
|
||||||
xfflush(port->file);
|
pic_errorf(pic, "get-output-bytevector: port is not made by open-output-bytevector");
|
||||||
size = (size_t)xftell(port->file);
|
}
|
||||||
xrewind(port->file);
|
|
||||||
|
|
||||||
/* copy to buf */
|
xfflush(port->file);
|
||||||
blob = pic_make_blob(pic, size);
|
|
||||||
xfread(blob->data, 1, size, port->file);
|
s = port->file->vtable.cookie;
|
||||||
|
|
||||||
|
blob = pic_make_blob(pic, s->end);
|
||||||
|
memcpy(blob->data, s->buf, s->end);
|
||||||
|
|
||||||
return pic_obj_value(blob);
|
return pic_obj_value(blob);
|
||||||
}
|
}
|
||||||
|
|
|
@ -856,11 +856,14 @@ pic_read(pic_state *pic, struct pic_port *port)
|
||||||
pic_value
|
pic_value
|
||||||
pic_read_cstr(pic_state *pic, const char *str)
|
pic_read_cstr(pic_state *pic, const char *str)
|
||||||
{
|
{
|
||||||
struct pic_port *port;
|
struct pic_port *port = pic_open_input_string(pic, str);
|
||||||
|
pic_value form;
|
||||||
|
|
||||||
port = pic_open_input_string(pic, str);
|
form = pic_read(pic, port);
|
||||||
|
|
||||||
return pic_read(pic, port);
|
pic_close_port(pic, port);
|
||||||
|
|
||||||
|
return form;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pic_value
|
static pic_value
|
||||||
|
|
|
@ -326,17 +326,17 @@ pic_open(int argc, char *argv[], char **envp, pic_allocf allocf)
|
||||||
/* reader */
|
/* reader */
|
||||||
pic->reader = pic_reader_open(pic);
|
pic->reader = pic_reader_open(pic);
|
||||||
|
|
||||||
|
/* standard I/O */
|
||||||
|
pic->xSTDIN = pic_make_standard_port(pic, xstdin, PIC_PORT_IN);
|
||||||
|
pic->xSTDOUT = pic_make_standard_port(pic, xstdout, PIC_PORT_OUT);
|
||||||
|
pic->xSTDERR = pic_make_standard_port(pic, xstderr, PIC_PORT_OUT);
|
||||||
|
|
||||||
/* standard libraries */
|
/* standard libraries */
|
||||||
pic->PICRIN_BASE = pic_open_library(pic, pic_read_cstr(pic, "(picrin base)"));
|
pic->PICRIN_BASE = pic_open_library(pic, pic_read_cstr(pic, "(picrin base)"));
|
||||||
pic->PICRIN_USER = pic_open_library(pic, pic_read_cstr(pic, "(picrin user)"));
|
pic->PICRIN_USER = pic_open_library(pic, pic_read_cstr(pic, "(picrin user)"));
|
||||||
pic->lib = pic->PICRIN_USER;
|
pic->lib = pic->PICRIN_USER;
|
||||||
pic->prev_lib = NULL;
|
pic->prev_lib = NULL;
|
||||||
|
|
||||||
/* standard I/O */
|
|
||||||
pic->xSTDIN = pic_make_standard_port(pic, xstdin, PIC_PORT_IN);
|
|
||||||
pic->xSTDOUT = pic_make_standard_port(pic, xstdout, PIC_PORT_OUT);
|
|
||||||
pic->xSTDERR = pic_make_standard_port(pic, xstderr, PIC_PORT_OUT);
|
|
||||||
|
|
||||||
pic_gc_arena_restore(pic, ai);
|
pic_gc_arena_restore(pic, ai);
|
||||||
|
|
||||||
/* turn on GC */
|
/* turn on GC */
|
||||||
|
|
|
@ -0,0 +1,472 @@
|
||||||
|
#include "picrin.h"
|
||||||
|
|
||||||
|
static int file_read(void *cookie, char *ptr, int size) {
|
||||||
|
FILE *file = cookie;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
size = 1; /* override size */
|
||||||
|
|
||||||
|
r = (int)fread(ptr, 1, (size_t)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 = cookie;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = (int)fwrite(ptr, 1, (size_t)size, file);
|
||||||
|
if (r < size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fflush(cookie);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long file_seek(void *cookie, long pos, int whence) {
|
||||||
|
switch (whence) {
|
||||||
|
case XSEEK_CUR:
|
||||||
|
whence = SEEK_CUR;
|
||||||
|
break;
|
||||||
|
case XSEEK_SET:
|
||||||
|
whence = SEEK_SET;
|
||||||
|
break;
|
||||||
|
case XSEEK_END:
|
||||||
|
whence = SEEK_END;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return fseek(cookie, pos, whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_close(void *cookie) {
|
||||||
|
return fclose(cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
xFILE *xfopen(const char *name, const char *mode) {
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if ((fp = fopen(name, mode)) == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (*mode) {
|
||||||
|
case 'r':
|
||||||
|
return xfunopen(fp, file_read, NULL, file_seek, file_close);
|
||||||
|
default:
|
||||||
|
return xfunopen(fp, NULL, file_write, file_seek, file_close);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FILE_VTABLE { 0, file_read, file_write, file_seek, file_close }
|
||||||
|
|
||||||
|
xFILE x_iob[XOPEN_MAX] = {
|
||||||
|
{ { 0 }, 0, NULL, NULL, FILE_VTABLE, X_READ },
|
||||||
|
{ { 0 }, 0, NULL, NULL, FILE_VTABLE, X_WRITE | X_LNBUF },
|
||||||
|
{ { 0 }, 0, NULL, NULL, FILE_VTABLE, X_WRITE | X_UNBUF }
|
||||||
|
};
|
||||||
|
|
||||||
|
xFILE *xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*close)(void *)) {
|
||||||
|
xFILE *fp;
|
||||||
|
|
||||||
|
for (fp = x_iob; fp < x_iob + XOPEN_MAX; fp++)
|
||||||
|
if ((fp->flag & (X_READ | X_WRITE)) == 0)
|
||||||
|
break; /* found free slot */
|
||||||
|
|
||||||
|
if (fp >= x_iob + XOPEN_MAX) /* no free slots */
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
fp->cnt = 0;
|
||||||
|
fp->base = NULL;
|
||||||
|
fp->flag = read? X_READ : X_WRITE;
|
||||||
|
|
||||||
|
fp->vtable.cookie = cookie;
|
||||||
|
fp->vtable.read = read;
|
||||||
|
fp->vtable.write = write;
|
||||||
|
fp->vtable.seek = seek;
|
||||||
|
fp->vtable.close = close;
|
||||||
|
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xfclose(xFILE *fp) {
|
||||||
|
xfflush(fp);
|
||||||
|
fp->flag = 0;
|
||||||
|
if (fp->base != fp->buf)
|
||||||
|
free(fp->base);
|
||||||
|
return fp->vtable.close(fp->vtable.cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
int x_fillbuf(xFILE *fp) {
|
||||||
|
int bufsize;
|
||||||
|
|
||||||
|
if ((fp->flag & (X_READ|X_EOF|X_ERR)) != X_READ)
|
||||||
|
return EOF;
|
||||||
|
if (fp->base == NULL) {
|
||||||
|
if ((fp->flag & X_UNBUF) == 0) {
|
||||||
|
/* no buffer yet */
|
||||||
|
if ((fp->base = malloc(XBUFSIZ)) == NULL) {
|
||||||
|
/* can't get buffer, try unbuffered */
|
||||||
|
fp->flag |= X_UNBUF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fp->flag & X_UNBUF) {
|
||||||
|
fp->base = fp->buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bufsize = (fp->flag & X_UNBUF) ? sizeof(fp->buf) : XBUFSIZ;
|
||||||
|
|
||||||
|
fp->ptr = fp->base;
|
||||||
|
fp->cnt = fp->vtable.read(fp->vtable.cookie, fp->ptr, bufsize);
|
||||||
|
|
||||||
|
if (--fp->cnt < 0) {
|
||||||
|
if (fp->cnt == -1)
|
||||||
|
fp->flag |= X_EOF;
|
||||||
|
else
|
||||||
|
fp->flag |= X_ERR;
|
||||||
|
fp->cnt = 0;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (unsigned char) *fp->ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x_flushbuf(int x, xFILE *fp) {
|
||||||
|
int num_written=0, bufsize=0;
|
||||||
|
char c = x;
|
||||||
|
|
||||||
|
if ((fp->flag & (X_WRITE|X_EOF|X_ERR)) != X_WRITE)
|
||||||
|
return EOF;
|
||||||
|
if (fp->base == NULL && ((fp->flag & X_UNBUF) == 0)) {
|
||||||
|
/* no buffer yet */
|
||||||
|
if ((fp->base = malloc(XBUFSIZ)) == NULL) {
|
||||||
|
/* couldn't allocate a buffer, so try unbuffered */
|
||||||
|
fp->flag |= X_UNBUF;
|
||||||
|
} else {
|
||||||
|
fp->ptr = fp->base;
|
||||||
|
fp->cnt = XBUFSIZ - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fp->flag & X_UNBUF) {
|
||||||
|
/* unbuffered write */
|
||||||
|
fp->ptr = fp->base = NULL;
|
||||||
|
fp->cnt = 0;
|
||||||
|
if (x == EOF)
|
||||||
|
return EOF;
|
||||||
|
num_written = fp->vtable.write(fp->vtable.cookie, (const char *) &c, 1);
|
||||||
|
bufsize = 1;
|
||||||
|
} else {
|
||||||
|
/* buffered write */
|
||||||
|
assert(fp->ptr);
|
||||||
|
if (x != EOF) {
|
||||||
|
*fp->ptr++ = (unsigned char) c;
|
||||||
|
}
|
||||||
|
bufsize = (int)(fp->ptr - fp->base);
|
||||||
|
while(bufsize - num_written > 0) {
|
||||||
|
int t;
|
||||||
|
t = fp->vtable.write(fp->vtable.cookie, fp->base + num_written, bufsize - num_written);
|
||||||
|
if (t < 0)
|
||||||
|
break;
|
||||||
|
num_written += t;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp->ptr = fp->base;
|
||||||
|
fp->cnt = BUFSIZ - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_written == bufsize) {
|
||||||
|
return x;
|
||||||
|
} else {
|
||||||
|
fp->flag |= X_ERR;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int xfflush(xFILE *f) {
|
||||||
|
int retval;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
retval = 0;
|
||||||
|
if (f == NULL) {
|
||||||
|
/* flush all output streams */
|
||||||
|
for (i = 0; i < XOPEN_MAX; i++) {
|
||||||
|
if ((x_iob[i].flag & X_WRITE) && (xfflush(&x_iob[i]) == -1))
|
||||||
|
retval = -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((f->flag & X_WRITE) == 0)
|
||||||
|
return -1;
|
||||||
|
x_flushbuf(EOF, f);
|
||||||
|
if (f->flag & X_ERR)
|
||||||
|
retval = -1;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xfputc(int x, xFILE *fp) {
|
||||||
|
return xputc(x, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int xfgetc(xFILE *fp) {
|
||||||
|
return xgetc(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int xfputs(const char *s, xFILE *stream) {
|
||||||
|
const char *ptr = s;
|
||||||
|
while(*ptr != '\0') {
|
||||||
|
if (xputc(*ptr, stream) == EOF)
|
||||||
|
return EOF;
|
||||||
|
++ptr;
|
||||||
|
}
|
||||||
|
return (int)(ptr - s);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *xfgets(char *s, int size, xFILE *stream) {
|
||||||
|
int c;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
xfflush(NULL);
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
buf = s;
|
||||||
|
while (--size > 0 && (c = xgetc(stream)) != EOF) {
|
||||||
|
if ((*buf++ = c) == '\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*buf = '\0';
|
||||||
|
|
||||||
|
return (c == EOF && buf == s) ? NULL : s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xputs(const char *s) {
|
||||||
|
int i = 1;
|
||||||
|
|
||||||
|
while(*s != '\0') {
|
||||||
|
if (xputchar(*s++) == EOF)
|
||||||
|
return EOF;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (xputchar('\n') == EOF) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *xgets(char *s) {
|
||||||
|
int c;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
xfflush(NULL);
|
||||||
|
|
||||||
|
buf = s;
|
||||||
|
while ((c = xgetchar()) != EOF && c != '\n') {
|
||||||
|
*buf++ = c;
|
||||||
|
}
|
||||||
|
*buf = '\0';
|
||||||
|
|
||||||
|
return (c == EOF && buf == s) ? NULL : s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xungetc(int c, xFILE *fp) {
|
||||||
|
unsigned char uc = c;
|
||||||
|
|
||||||
|
if (c == EOF || fp->base == fp->ptr) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
fp->cnt++;
|
||||||
|
return *--fp->ptr = uc;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t xfread(void *ptr, size_t size, size_t count, xFILE *fp) {
|
||||||
|
long nbytes;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
nbytes = size * count;
|
||||||
|
while (nbytes > fp->cnt) {
|
||||||
|
memcpy((char *)ptr, fp->ptr, fp->cnt);
|
||||||
|
fp->ptr += fp->cnt;
|
||||||
|
ptr += fp->cnt;
|
||||||
|
nbytes -= fp->cnt;
|
||||||
|
if ((c = x_fillbuf(fp)) == EOF) {
|
||||||
|
return (size * count - nbytes) / size;
|
||||||
|
} else {
|
||||||
|
xungetc(c, fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memcpy((char *)ptr, fp->ptr, nbytes);
|
||||||
|
fp->ptr += nbytes;
|
||||||
|
fp->cnt -= nbytes;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t xfwrite(const void *ptr, size_t size, size_t count, xFILE *fp) {
|
||||||
|
long nbytes;
|
||||||
|
|
||||||
|
nbytes = size * count;
|
||||||
|
while (nbytes > fp->cnt) {
|
||||||
|
memcpy(fp->ptr, (char *)ptr, fp->cnt);
|
||||||
|
fp->ptr += fp->cnt;
|
||||||
|
ptr += fp->cnt;
|
||||||
|
nbytes -= fp->cnt;
|
||||||
|
if (x_flushbuf(EOF, fp) == EOF) {
|
||||||
|
return (size * count - nbytes) / size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memcpy(fp->ptr, (char *)ptr, nbytes);
|
||||||
|
fp->ptr += nbytes;
|
||||||
|
fp->cnt -= nbytes;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
long xfseek(xFILE *fp, long offset, int whence) {
|
||||||
|
long s;
|
||||||
|
|
||||||
|
xfflush(fp);
|
||||||
|
|
||||||
|
fp->ptr = fp->base;
|
||||||
|
fp->cnt = 0;
|
||||||
|
|
||||||
|
if ((s = fp->vtable.seek(fp->vtable.cookie, offset, whence)) != 0)
|
||||||
|
return s;
|
||||||
|
fp->flag &= ~X_EOF;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
long xftell(xFILE *fp) {
|
||||||
|
return xfseek(fp, 0, XSEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xrewind(xFILE *fp) {
|
||||||
|
xfseek(fp, 0, XSEEK_SET);
|
||||||
|
xclearerr(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int print_int(xFILE *stream, long x, int base) {
|
||||||
|
static char digits[] = "0123456789abcdef";
|
||||||
|
char buf[20];
|
||||||
|
int i, c, neg;
|
||||||
|
|
||||||
|
neg = 0;
|
||||||
|
if (x < 0) {
|
||||||
|
neg = 1;
|
||||||
|
x = -x;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
buf[i++] = digits[x % base];
|
||||||
|
} while ((x /= base) != 0);
|
||||||
|
|
||||||
|
if (neg) {
|
||||||
|
buf[i++] = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
c = i;
|
||||||
|
while (i-- > 0) {
|
||||||
|
xputc(buf[i], stream);
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xvfprintf(xFILE *stream, const char *fmt, va_list ap) {
|
||||||
|
const char *p;
|
||||||
|
char *sval;
|
||||||
|
int ival;
|
||||||
|
#if PIC_ENABLE_FLOAT
|
||||||
|
double dval;
|
||||||
|
#endif
|
||||||
|
void *vp;
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
for (p = fmt; *p; p++) {
|
||||||
|
if (*p != '%') {
|
||||||
|
xputc(*p, stream);
|
||||||
|
cnt++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (*++p) {
|
||||||
|
case 'd':
|
||||||
|
case 'i':
|
||||||
|
ival = va_arg(ap, int);
|
||||||
|
cnt += print_int(stream, ival, 10);
|
||||||
|
break;
|
||||||
|
#if PIC_ENABLE_FLOAT
|
||||||
|
case 'f':
|
||||||
|
dval = va_arg(ap, double);
|
||||||
|
cnt += print_int(stream, dval, 10);
|
||||||
|
xputc('.', stream);
|
||||||
|
cnt++;
|
||||||
|
if ((ival = fabs((dval - floor(dval)) * 1e4) + 0.5) == 0) {
|
||||||
|
cnt += xfputs("0000", stream);
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 3 - (int)log10(ival); ++i) {
|
||||||
|
xputc('0', stream);
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
cnt += print_int(stream, ival, 10);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 's':
|
||||||
|
sval = va_arg(ap, char*);
|
||||||
|
cnt += xfputs(sval, stream);
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
vp = va_arg(ap, void*);
|
||||||
|
cnt += xfputs("0x", stream);
|
||||||
|
cnt += print_int(stream, (long)vp, 16);
|
||||||
|
break;
|
||||||
|
case '%':
|
||||||
|
xputc(*(p-1), stream);
|
||||||
|
cnt++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
xputc('%', stream);
|
||||||
|
xputc(*(p-1), stream);
|
||||||
|
cnt += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
|
xgets(buf);
|
||||||
|
|
||||||
|
xprintf("%s\n", buf);
|
||||||
|
xprintf("hello\n");
|
||||||
|
xprintf("hello\n");
|
||||||
|
// xfflush(0);
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
Reference in New Issue