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