import xhash, xrope, xfile, and xvect

This commit is contained in:
Yuichi Nishiwaki 2014-08-25 16:21:55 +09:00
parent aa3b385e27
commit 1861aff2d1
5 changed files with 1444 additions and 0 deletions

78
include/picrin/xfile.h Normal file
View File

@ -0,0 +1,78 @@
#ifndef XFILE_H__
#define XFILE_H__
#if defined(__cplusplus)
extern "C" {
#endif
#include <stddef.h>
#include <stdarg.h>
#include <stdio.h>
typedef struct {
int ungot;
int flags;
/* operators */
struct {
void *cookie;
int (*read)(void *, char *, int);
int (*write)(void *, const char *, int);
long (*seek)(void *, long, int);
int (*flush)(void *);
int (*close)(void *);
} vtable;
} xFILE;
/* generic file constructor */
xFILE *xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*flush)(void *), int (*close)(void *));
/* resource aquisition */
xFILE *xfopen(const char *, const char *);
xFILE *xfpopen(FILE *);
xFILE *xmopen();
int xfclose(xFILE *);
/* buffer management */
int xfflush(xFILE *);
/* direct IO with buffering */
size_t xfread(void *, size_t, size_t, xFILE *);
size_t xfwrite(const void *, size_t, size_t, xFILE *);
/* indicator positioning */
long xfseek(xFILE *, long offset, int whence);
long xftell(xFILE *);
void xrewind(xFILE *);
/* stream status */
void xclearerr(xFILE *);
int xfeof(xFILE *);
int xferror(xFILE *);
/* character IO */
int xfgetc(xFILE *);
char *xfgets(char *, int, xFILE *);
int xfputc(int, xFILE *);
int xfputs(const char *, xFILE *);
char xgetc(xFILE *);
int xgetchar(void);
int xputc(int, xFILE *);
int xputchar(int);
int xputs(char *);
int xungetc(int, xFILE *);
/* formatted I/O */
int xprintf(const char *, ...);
int xfprintf(xFILE *, const char *, ...);
int xvfprintf(xFILE *, const char *, va_list);
/* standard I/O */
extern xFILE *xstdin;
extern xFILE *xstdout;
extern xFILE *xstderr;
#if defined(__cplusplus)
}
#endif
#endif

407
include/picrin/xhash.h Normal file
View File

@ -0,0 +1,407 @@
#ifndef XHASH_H__
#define XHASH_H__
/*
* Copyright (c) 2013-2014 by Yuichi Nishiwaki <yuichi.nishiwaki@gmail.com>
*/
#if defined(__cplusplus)
extern "C" {
#endif
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>
/* simple object to object hash table */
#define XHASH_INIT_SIZE 11
#define XHASH_RESIZE_RATIO 0.75
#define XHASH_ALIGNMENT 3 /* quad word alignment */
#define XHASH_MASK (~((1 << XHASH_ALIGNMENT) - 1))
#define XHASH_ALIGN(i) ((((i) - 1) & XHASH_MASK) + (1 << XHASH_ALIGNMENT))
typedef struct xh_entry {
struct xh_entry *next;
int hash;
const char *key; /* == val + XHASH_ALIGN(vwidth) */
char val[];
} xh_entry;
#define xh_key(e,type) (*(type *)((e)->key))
#define xh_val(e,type) (*(type *)((e)->val))
typedef int (*xh_hashf)(const void *, void *);
typedef int (*xh_equalf)(const void *, const void *, void *);
typedef struct xhash {
xh_entry **buckets;
size_t size, count, kwidth, vwidth;
xh_hashf hashf;
xh_equalf equalf;
void *data;
} xhash;
static inline void xh_init_(xhash *x, size_t, size_t, xh_hashf, xh_equalf, void *);
static inline xh_entry *xh_get_(xhash *x, const void *key);
static inline xh_entry *xh_put_(xhash *x, const void *key, void *val);
static inline void xh_del_(xhash *x, const void *key);
static inline void xh_clear(xhash *x);
static inline void xh_destroy(xhash *x);
/* string map */
static inline void xh_init_str(xhash *x, size_t width);
static inline xh_entry *xh_get_str(xhash *x, const char *key);
static inline xh_entry *xh_put_str(xhash *x, const char *key, void *);
static inline void xh_del_str(xhash *x, const char *key);
/* object map */
static inline void xh_init_ptr(xhash *x, size_t width);
static inline xh_entry *xh_get_ptr(xhash *x, const void *key);
static inline xh_entry *xh_put_ptr(xhash *x, const void *key, void *);
static inline void xh_del_ptr(xhash *x, const void *key);
/* int map */
static inline void xh_init_int(xhash *x, size_t width);
static inline xh_entry *xh_get_int(xhash *x, int key);
static inline xh_entry *xh_put_int(xhash *x, int key, void *);
static inline void xh_del_int(xhash *x, int key);
typedef struct xh_iter {
xhash *x;
xh_entry *e, *next;
size_t bidx;
} xh_iter;
static inline void xh_begin(xh_iter *it, xhash *x);
static inline int xh_next(xh_iter *it);
static inline void
xh_bucket_realloc(xhash *x, size_t newsize)
{
x->size = newsize;
x->buckets = realloc(x->buckets, (x->size + 1) * sizeof(xh_entry *));
memset(x->buckets, 0, (x->size + 1) * sizeof(xh_entry *));
}
static inline void
xh_init_(xhash *x, size_t kwidth, size_t vwidth, xh_hashf hashf, xh_equalf equalf, void *data)
{
x->size = 0;
x->buckets = NULL;
x->count = 0;
x->kwidth = kwidth;
x->vwidth = vwidth;
x->hashf = hashf;
x->equalf = equalf;
x->data = data;
xh_bucket_realloc(x, XHASH_INIT_SIZE);
}
static inline xh_entry *
xh_get_(xhash *x, const void *key)
{
int hash;
size_t idx;
xh_entry *e;
hash = x->hashf(key, x->data);
idx = ((unsigned)hash) % x->size;
for (e = x->buckets[idx]; e; e = e->next) {
if (e->hash == hash && x->equalf(key, e->key, x->data))
break;
}
return e;
}
static inline void
xh_resize_(xhash *x, size_t newsize)
{
xhash y;
xh_iter it;
size_t idx;
xh_init_(&y, x->kwidth, x->vwidth, x->hashf, x->equalf, x->data);
xh_bucket_realloc(&y, newsize);
xh_begin(&it, x);
while (xh_next(&it)) {
idx = ((unsigned)it.e->hash) % y.size;
/* reuse entry object */
it.e->next = y.buckets[idx];
y.buckets[idx] = it.e;
y.count++;
}
free(x->buckets);
/* copy all members from y to x */
memcpy(x, &y, sizeof(xhash));
}
static inline xh_entry *
xh_put_(xhash *x, const void *key, void *val)
{
int hash;
size_t idx;
xh_entry *e;
if ((e = xh_get_(x, key))) {
memcpy(e->val, val, x->vwidth);
return e;
}
if (x->count + 1 > x->size * XHASH_RESIZE_RATIO) {
xh_resize_(x, x->size * 2 + 1);
}
hash = x->hashf(key, x->data);
idx = ((unsigned)hash) % x->size;
e = (xh_entry *)malloc(offsetof(xh_entry, val) + XHASH_ALIGN(x->vwidth) + x->kwidth);
e->next = x->buckets[idx];
e->hash = hash;
e->key = e->val + XHASH_ALIGN(x->vwidth);
memcpy((void *)e->key, key, x->kwidth);
memcpy(e->val, val, x->vwidth);
x->count++;
return x->buckets[idx] = e;
}
static inline void
xh_del_(xhash *x, const void *key)
{
int hash;
size_t idx;
xh_entry *e, *d;
hash = x->hashf(key, x->data);
idx = ((unsigned)hash) % x->size;
if (x->buckets[idx]->hash == hash && x->equalf(key, x->buckets[idx]->key, x->data)) {
e = x->buckets[idx]->next;
free(x->buckets[idx]);
x->buckets[idx] = e;
}
else {
for (e = x->buckets[idx]; ; e = e->next) {
if (e->next->hash == hash && x->equalf(key, e->next->key, x->data))
break;
}
d = e->next->next;
free(e->next);
e->next = d;
}
x->count--;
}
static inline void
xh_clear(xhash *x)
{
size_t i;
xh_entry *e, *d;
for (i = 0; i < x->size; ++i) {
e = x->buckets[i];
while (e) {
d = e->next;
free(e);
e = d;
}
x->buckets[i] = NULL;
}
x->count = 0;
}
static inline void
xh_destroy(xhash *x)
{
xh_clear(x);
free(x->buckets);
}
/* string map */
static inline int
xh_str_hash(const void *key, void *data)
{
const char *str = *(const char **)key;
int hash = 0;
(void)data;
while (*str) {
hash = hash * 31 + *str++;
}
return hash;
}
static inline int
xh_str_equal(const void *key1, const void *key2, void *data)
{
(void)data;
return strcmp(*(const char **)key1, *(const char **)key2) == 0;
}
static inline void
xh_init_str(xhash *x, size_t width)
{
xh_init_(x, sizeof(const char *), width, xh_str_hash, xh_str_equal, NULL);
}
static inline xh_entry *
xh_get_str(xhash *x, const char *key)
{
return xh_get_(x, &key);
}
static inline xh_entry *
xh_put_str(xhash *x, const char *key, void *val)
{
return xh_put_(x, &key, val);
}
static inline void
xh_del_str(xhash *x, const char *key)
{
xh_del_(x, &key);
}
/* object map */
static inline int
xh_ptr_hash(const void *key, void *data)
{
(void)data;
return (size_t)*(const void **)key;
}
static inline int
xh_ptr_equal(const void *key1, const void *key2, void *data)
{
(void) data;
return *(const void **)key1 == *(const void **)key2;
}
static inline void
xh_init_ptr(xhash *x, size_t width)
{
xh_init_(x, sizeof(const void *), width, xh_ptr_hash, xh_ptr_equal, NULL);
}
static inline xh_entry *
xh_get_ptr(xhash *x, const void *key)
{
return xh_get_(x, &key);
}
static inline xh_entry *
xh_put_ptr(xhash *x, const void *key, void *val)
{
return xh_put_(x, &key, val);
}
static inline void
xh_del_ptr(xhash *x, const void *key)
{
xh_del_(x, &key);
}
/* int map */
static inline int
xh_int_hash(const void *key, void *data)
{
(void)data;
return *(int *)key;
}
static inline int
xh_int_equal(const void *key1, const void *key2, void *data)
{
(void)data;
return *(int *)key1 == *(int *)key2;
}
static inline void
xh_init_int(xhash *x, size_t width)
{
xh_init_(x, sizeof(int), width, xh_int_hash, xh_int_equal, NULL);
}
static inline xh_entry *
xh_get_int(xhash *x, int key)
{
return xh_get_(x, &key);
}
static inline xh_entry *
xh_put_int(xhash *x, int key, void *val)
{
return xh_put_(x, &key, val);
}
static inline void
xh_del_int(xhash *x, int key)
{
xh_del_(x, &key);
}
/** iteration */
static inline void
xh_begin(xh_iter *it, xhash *x)
{
size_t bidx;
it->x = x;
for (bidx = 0; bidx < x->size; ++bidx) {
if (x->buckets[bidx])
break;
}
it->e = NULL;
it->next = x->buckets[bidx];
it->bidx = bidx;
}
static inline int
xh_next(xh_iter *it)
{
size_t bidx;
if (! it->next) {
return 0;
}
it->e = it->next;
if (it->next->next) {
it->next = it->next->next;
return 1;
}
for (bidx = it->bidx + 1; bidx < it->x->size; ++bidx) {
if (it->x->buckets[bidx])
break;
}
it->next = it->x->buckets[bidx];
it->bidx = bidx;
return 1;
}
#if defined(__cplusplus)
}
#endif
#endif

329
include/picrin/xrope.h Normal file
View File

@ -0,0 +1,329 @@
#ifndef XROPE_H__
#define XROPE_H__
#if defined(__cplusplus)
extern "C" {
#endif
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/* public APIs */
typedef struct xrope xrope;
/**
* | name | frees buffer? | end with NULL? | complexity | misc
* | ---- | ---- | ---- | ---- | ---
* | xr_new_cstr | no | yes | O(1) | xr_new(_lit)
* | xr_new_imbed | no | no | O(1) |
* | xr_new_move | yes | yes | O(1) |
* | xr_new_copy | yes | no | O(n) |
*/
#define xr_new(cstr) xr_new_cstr(cstr, strlen(cstr))
#define xr_new_lit(cstr) xr_new_cstr(cstr, sizeof(cstr) - 1)
static inline xrope *xr_new_cstr(const char *, size_t);
static inline xrope *xr_new_imbed(const char *, size_t);
static inline xrope *xr_new_move(const char *, size_t);
static inline xrope *xr_new_copy(const char *, size_t);
static inline void XROPE_INCREF(xrope *);
static inline void XROPE_DECREF(xrope *);
static inline size_t xr_len(xrope *);
static inline char xr_at(xrope *, size_t);
static inline xrope *xr_cat(xrope *, xrope *);
static inline xrope *xr_sub(xrope *, size_t, size_t);
static inline const char *xr_cstr(xrope *); /* returns NULL-terminated string */
/* impl */
typedef struct {
char *str;
int refcnt;
size_t len;
char autofree, zeroterm;
} xr_chunk;
#define XR_CHUNK_INCREF(c) do { \
(c)->refcnt++; \
} while (0)
#define XR_CHUNK_DECREF(c) do { \
xr_chunk *c__ = (c); \
if (! --c__->refcnt) { \
if (c__->autofree) \
free(c__->str); \
free(c__); \
} \
} while (0)
struct xrope {
int refcnt;
size_t weight;
xr_chunk *chunk;
size_t offset;
struct xrope *left, *right;
};
static inline void
XROPE_INCREF(xrope *x) {
x->refcnt++;
}
static inline void
XROPE_DECREF(xrope *x) {
if (! --x->refcnt) {
if (x->chunk) {
XR_CHUNK_DECREF(x->chunk);
free(x);
return;
}
XROPE_DECREF(x->left);
XROPE_DECREF(x->right);
free(x);
}
}
static inline xrope *
xr_new_cstr(const char *cstr, size_t len)
{
xr_chunk *c;
xrope *x;
c = (xr_chunk *)malloc(sizeof(xr_chunk));
c->refcnt = 1;
c->str = (char *)cstr;
c->len = len;
c->autofree = 0;
c->zeroterm = 1;
x = (xrope *)malloc(sizeof(xrope));
x->refcnt = 1;
x->left = NULL;
x->right = NULL;
x->weight = c->len;
x->offset = 0;
x->chunk = c;
return x;
}
static inline xrope *
xr_new_imbed(const char *str, size_t len)
{
xr_chunk *c;
xrope *x;
c = (xr_chunk *)malloc(sizeof(xr_chunk));
c->refcnt = 1;
c->str = (char *)str;
c->len = len;
c->autofree = 0;
c->zeroterm = 0;
x = (xrope *)malloc(sizeof(xrope));
x->refcnt = 1;
x->left = NULL;
x->right = NULL;
x->weight = c->len;
x->offset = 0;
x->chunk = c;
return x;
}
static inline xrope *
xr_new_move(const char *cstr, size_t len)
{
xr_chunk *c;
xrope *x;
c = (xr_chunk *)malloc(sizeof(xr_chunk));
c->refcnt = 1;
c->str = (char *)cstr;
c->len = len;
c->autofree = 1;
c->zeroterm = 1;
x = (xrope *)malloc(sizeof(xrope));
x->refcnt = 1;
x->left = NULL;
x->right = NULL;
x->weight = c->len;
x->offset = 0;
x->chunk = c;
return x;
}
static inline xrope *
xr_new_copy(const char *str, size_t len)
{
char *buf;
xr_chunk *c;
xrope *x;
buf = (char *)malloc(len + 1);
buf[len] = '\0';
memcpy(buf, str, len);
c = (xr_chunk *)malloc(sizeof(xr_chunk));
c->refcnt = 1;
c->str = buf;
c->len = len;
c->autofree = 1;
c->zeroterm = 1;
x = (xrope *)malloc(sizeof(xrope));
x->refcnt = 1;
x->left = NULL;
x->right = NULL;
x->weight = c->len;
x->offset = 0;
x->chunk = c;
return x;
}
static inline size_t
xr_len(xrope *x)
{
return x->weight;
}
static inline char
xr_at(xrope *x, size_t i)
{
if (x->weight <= i) {
return -1;
}
if (x->chunk) {
return x->chunk->str[x->offset + i];
}
return (i < x->left->weight)
? xr_at(x->left, i)
: xr_at(x->right, i - x->left->weight);
}
static inline xrope *
xr_cat(xrope *x, xrope *y)
{
xrope *z;
z = (xrope *)malloc(sizeof(xrope));
z->refcnt = 1;
z->left = x;
z->right = y;
z->weight = x->weight + y->weight;
z->offset = 0;
z->chunk = NULL;
XROPE_INCREF(x);
XROPE_INCREF(y);
return z;
}
static inline struct xrope *
xr_sub(xrope *x, size_t i, size_t j)
{
assert(i <= j);
assert(j <= x->weight);
if (i == 0 && x->weight == j) {
XROPE_INCREF(x);
return x;
}
if (x->chunk) {
xrope *y;
y = (xrope *)malloc(sizeof(xrope));
y->refcnt = 1;
y->left = NULL;
y->right = NULL;
y->weight = j - i;
y->offset = x->offset + i;
y->chunk = x->chunk;
XR_CHUNK_INCREF(x->chunk);
return y;
}
if (j <= x->left->weight) {
return xr_sub(x->left, i, j);
}
else if (x->left->weight <= i) {
return xr_sub(x->right, i - x->left->weight, j - x->left->weight);
}
else {
xrope *r, *l;
l = xr_sub(x->left, i, x->left->weight);
r = xr_sub(x->right, 0, j - x->left->weight);
x = xr_cat(l, r);
XROPE_DECREF(l);
XROPE_DECREF(r);
return x;
}
}
static inline void
xr_fold(xrope *x, xr_chunk *c, size_t offset)
{
if (x->chunk) {
memcpy(c->str + offset, x->chunk->str + x->offset, x->weight);
XR_CHUNK_DECREF(x->chunk);
x->chunk = c;
x->offset = offset;
XR_CHUNK_INCREF(c);
return;
}
xr_fold(x->left, c, offset);
xr_fold(x->right, c, offset + x->left->weight);
XROPE_DECREF(x->left);
XROPE_DECREF(x->right);
x->left = x->right = NULL;
x->chunk = c;
x->offset = offset;
XR_CHUNK_INCREF(c);
}
static inline const char *
xr_cstr(xrope *x)
{
xr_chunk *c;
if (x->chunk && x->offset == 0 && x->weight == x->chunk->len && x->chunk->zeroterm) {
return x->chunk->str; /* reuse cached chunk */
}
c = (xr_chunk *)malloc(sizeof(xr_chunk));
c->refcnt = 1;
c->len = x->weight;
c->autofree = 1;
c->zeroterm = 1;
c->str = (char *)malloc(c->len + 1);
c->str[c->len] = '\0';
xr_fold(x, c, 0);
XR_CHUNK_DECREF(c);
return c->str;
}
#if defined(__cplusplus)
}
#endif
#endif

185
include/picrin/xvect.h Normal file
View File

@ -0,0 +1,185 @@
#ifndef XVECT_H__
#define XVECT_H__
/*
* Copyright (c) 2014 by Yuichi Nishiwaki <yuichi@idylls.jp>
*/
#if defined(__cplusplus)
extern "C" {
#endif
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
typedef struct xvect {
char *data;
size_t size, mask, head, tail, width;
} xvect;
static inline void xv_init(xvect *, size_t);
static inline void xv_destroy(xvect *);
static inline size_t xv_size(xvect *);
static inline void xv_reserve(xvect *, size_t);
static inline void xv_shrink(xvect *, size_t);
static inline void *xv_get(xvect *, size_t);
static inline void xv_set(xvect *, size_t, void *);
static inline void xv_push(xvect *, void *);
static inline void *xv_pop(xvect *);
static inline void *xv_shift(xvect *);
static inline void xv_unshift(xvect *, void *);
static inline void xv_splice(xvect *, size_t, ptrdiff_t);
static inline void xv_insert(xvect *, size_t, void *);
static inline void
xv_init(xvect *x, size_t width)
{
x->data = NULL;
x->width = width;
x->size = 0;
x->mask = -1;
x->head = 0;
x->tail = 0;
}
static inline void
xv_destroy(xvect *x)
{
free(x->data);
}
static inline size_t
xv_size(xvect *x)
{
return x->tail < x->head
? x->tail + x->size - x->head
: x->tail - x->head;
}
static inline size_t
xv_round2(size_t x)
{
x -= 1;
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
x |= (x >> 32);
x++;
return x;
}
static inline void
xv_rotate(xvect *x)
{
if (x->tail < x->head) {
char buf[x->size * x->width];
/* perform rotation */
memcpy(buf, x->data, sizeof buf);
memcpy(x->data, buf + x->head * x->width, (x->size - x->head) * x->width);
memcpy(x->data + (x->size - x->head) * x->width, buf, x->tail * x->width);
x->tail = x->size - x->head + x->tail;
x->head = 0;
}
}
static inline void
xv_adjust(xvect *x, size_t size)
{
size = xv_round2(size);
if (size != x->size) {
xv_rotate(x);
x->data = realloc(x->data, size * x->width);
x->size = size;
x->mask = size - 1;
}
}
static inline void
xv_reserve(xvect *x, size_t mincapa)
{
if (x->size < mincapa + 1) {
xv_adjust(x, mincapa + 1); /* capa == size - 1 */
}
}
static inline void
xv_shrink(xvect *x, size_t maxcapa)
{
if (x->size > maxcapa + 1) {
xv_adjust(x, maxcapa + 1); /* capa == size - 1 */
}
}
static inline void *
xv_get(xvect *x, size_t i)
{
return x->data + ((x->head + x->size + i) & x->mask) * x->width;
}
static inline void
xv_set(xvect *x, size_t i, void *src)
{
memcpy(xv_get(x, i), src, x->width);
}
static inline void
xv_push(xvect *x, void *src)
{
xv_reserve(x, xv_size(x) + 1);
xv_set(x, xv_size(x), src);
x->tail = (x->tail + 1) & x->mask;
}
static inline void *
xv_pop(xvect *x)
{
x->tail = (x->tail + x->size - 1) & x->mask;
return xv_get(x, xv_size(x));
}
static inline void *
xv_shift(xvect *x)
{
x->head = (x->head + 1) & x->mask;
return xv_get(x, -1);
}
static inline void
xv_unshift(xvect *x, void *src)
{
xv_reserve(x, xv_size(x) + 1);
xv_set(x, -1, src);
x->head = (x->head + x->size - 1) & x->mask;
}
static inline void
xv_splice(xvect *x, size_t i, ptrdiff_t c)
{
xv_reserve(x, xv_size(x) - c);
xv_rotate(x);
memmove(xv_get(x, i), xv_get(x, i + c), (xv_size(x) - i - c) * x->width);
x->tail -= c;
}
static inline void
xv_insert(xvect *x, size_t i, void *src)
{
xv_splice(x, i, -1);
xv_set(x, i, src);
}
#if defined(__cplusplus)
}
#endif
#endif

445
xfile.c Normal file
View File

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